I am building a CRUD app using Flask and mySQL without ORM (mostly because I want to be better at SQL and SQLAlchemy is very high level). However, I am concerned about the design and separation of concerns.
This is the overall overview of my application, it's a multi-choice question bank for students (it's far to be done)
blueprints/ ----> admin/
user/
questions/
static/
templates/
app.py
database.py
If I am taking the admin/ folder I currently have 2 files (the structure is very similar for every blueprints)
admin/views.py
admin/templates/new-question.html
views.py
from flask import Blueprint, render_template, request
import pymysql
from prepsmarter.extensions import conn #my database pymysql conn variable
admin = Blueprint('admin', __name__, template_folder='templates')
@admin.route('/users', methods=['GET'])
def get_users():
sql = "SELECT category_id, category_text FROM category"
cursor = conn.cursor()
cursor.execute(sql)
categories = cursor.fetchall()
return render_template('admin/new-question.html', categories=categories)
def insert_answers(question_id, answer_letter, answer_value, correct_answer):
is_correct = 0
if answer_letter == correct_answer:
is_correct = 1
sql_answer = "INSERT INTO answers (question_id, answer_letter, answer_value, is_correct) VALUES(%s, %s, %s, %s)"
cursor = conn.cursor()
cursor.execute(sql_answer, (question_id, answer_letter, answer_value, is_correct))
cursor.fetchall()
conn.commit()
@admin.route('/add_contributor',methods = ['POST'])
def add_contributor():
name = request.form.get('contrib_name')
category = request.form.get('category_id')
question = request.form.get('question')
answer_a = request.form.get('answer_a')
answer_b = request.form.get('answer_b')
answer_c = request.form.get('answer_c')
correct_answer = request.form.get('correct_answer')
sql_1 = "INSERT INTO contributors (name) VALUES (%s)"
sql_3 = "INSERT INTO questions (contributor_id, question_text, category_id) VALUES (%s, %s, %s)"
cursor = conn.cursor()
cursor.execute(sql_1, name)
cursor.fetchall()
contrib_id = cursor.lastrowid
conn.commit()
cursor_3 = conn.cursor()
cursor_3.execute(sql_3, (contrib_id,question, category))
cursor_3.fetchall()
question_id = cursor_3.lastrowid
conn.commit()
insert_answers(question_id, "A", answer_a, correct_answer)
insert_answers(question_id, "B", answer_b, correct_answer)
insert_answers(question_id, "C", answer_c, correct_answer)
return "ok"
new-question.html
<body>
<section>
<form method="POST" action="{{url_for('admin.add_contributor')}}">
<div>
<label for="contrib_name">Name</label>
<input type="text" name="contrib_name">
</div>
<div>
<label for="category">category</label>
<select name="category_id" id="">
{% for category in categories %}
<option value="{{ category[0] }}">{{category[1]}}</option>
{% endfor %}
</select>
</div>
<div>
<label for="question">Question</label>
<textarea name="question" cols="30" rows="10"></textarea>
</div>
<div>
<label for="answer_a">Answer A</label>
<input type="text" name="answer_a">
</div>
<div>
<label for="answer_b">Answer B</label>
<input type="text" name="answer_b">
</div>
<div>
<label for="answer_c">Answer C</label>
<input type="text" name="answer_c">
</div>
<div>
<select name="correct_answer" id="">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>
</div>
<button type="submit">Submit</button>
</form>
</section>
</body>
Should I make a Python class to represent a question as an Object? I am not sure if it's a good practice to directly write SQL code under every methods on my routes.py, every Flask code I saw online is using ORM so not quite confident.
If I am making a class I will clearly have those attributes (which as split into 3 different tables on my db: category, questions, answers).
- Category
- Question-text
- Answers
- Correct Answer
- Contributor