title: Flask without ORM - Best practices
body: <p>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.</p>
  <p>This is the overall overview of my application, it's a multi-choice question bank for students (it's far to be done)</p>
  <pre><code>blueprints/ ----&gt; admin/
                    user/
                    questions/  
  static/
  templates/
  app.py
  database.py
  </code></pre>
  <p>If I am taking the admin/ folder I currently have 2 files (the structure is very similar for every blueprints)</p>
  <pre><code>admin/views.py
  admin/templates/new-question.html
  </code></pre>
  <p><strong>views.py</strong></p>
  <pre><code>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 = &quot;SELECT category_id, category_text FROM category&quot;
      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 = &quot;INSERT INTO answers (question_id, answer_letter, answer_value, is_correct) VALUES(%s, %s, %s, %s)&quot;
      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 = &quot;INSERT INTO contributors (name) VALUES (%s)&quot;
      sql_3 = &quot;INSERT INTO questions (contributor_id, question_text, category_id) VALUES (%s, %s, %s)&quot;
          
          
      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, &quot;A&quot;, answer_a, correct_answer)
      insert_answers(question_id, &quot;B&quot;, answer_b, correct_answer)
      insert_answers(question_id, &quot;C&quot;, answer_c, correct_answer)
      
  
      return &quot;ok&quot;
  </code></pre>
  <p><strong>new-question.html</strong></p>
  <pre><code>&lt;body&gt;
      &lt;section&gt;
          &lt;form method=&quot;POST&quot; action=&quot;{{url_for('admin.add_contributor')}}&quot;&gt;
              &lt;div&gt;
                  &lt;label for=&quot;contrib_name&quot;&gt;Name&lt;/label&gt;
                  &lt;input type=&quot;text&quot; name=&quot;contrib_name&quot;&gt;
              &lt;/div&gt;
  
              &lt;div&gt;
                  &lt;label for=&quot;category&quot;&gt;category&lt;/label&gt;
                  &lt;select name=&quot;category_id&quot; id=&quot;&quot;&gt;
                      {% for category in categories %}
                          &lt;option value=&quot;{{ category[0] }}&quot;&gt;{{category[1]}}&lt;/option&gt;
                      {% endfor %}
                  &lt;/select&gt;
              &lt;/div&gt;
  
              &lt;div&gt;
                  &lt;label for=&quot;question&quot;&gt;Question&lt;/label&gt;
              &lt;textarea name=&quot;question&quot; cols=&quot;30&quot; rows=&quot;10&quot;&gt;&lt;/textarea&gt;
              &lt;/div&gt;
  
              &lt;div&gt;
                  &lt;label for=&quot;answer_a&quot;&gt;Answer A&lt;/label&gt;
                  &lt;input type=&quot;text&quot; name=&quot;answer_a&quot;&gt;  
              &lt;/div&gt;
  
              &lt;div&gt;
                  &lt;label for=&quot;answer_b&quot;&gt;Answer B&lt;/label&gt;
                  &lt;input type=&quot;text&quot; name=&quot;answer_b&quot;&gt;  
              &lt;/div&gt;
  
              &lt;div&gt;
                  &lt;label for=&quot;answer_c&quot;&gt;Answer C&lt;/label&gt;
                  &lt;input type=&quot;text&quot; name=&quot;answer_c&quot;&gt;  
              &lt;/div&gt;
  
              &lt;div&gt;
                  &lt;select name=&quot;correct_answer&quot; id=&quot;&quot;&gt;
                      &lt;option value=&quot;A&quot;&gt;A&lt;/option&gt;
                      &lt;option value=&quot;B&quot;&gt;B&lt;/option&gt;
                      &lt;option value=&quot;C&quot;&gt;C&lt;/option&gt;
                  &lt;/select&gt;
              &lt;/div&gt;
  
   
              &lt;button type=&quot;submit&quot;&gt;Submit&lt;/button&gt;
          &lt;/form&gt;
      &lt;/section&gt;
  &lt;/body&gt;
  </code></pre>
  <p>Should I make a Python class to represent a <code>question</code> as an Object? I am not sure if it's a good practice to directly write SQL code under every methods on my <code>routes.py</code>, every Flask code I saw online is using ORM so not quite confident.</p>
  <p>If I am making a class I will clearly have those attributes (which as split into 3 different tables on my db: <code>category, questions, answers</code>).</p>
  <ul>
  <li>Category</li>
  <li>Question-text</li>
  <li>Answers</li>
  <li>Correct Answer</li>
  <li>Contributor</li>
  </ul>