Advertisement

A Flask App with Model

Madanasekaran.P

Flask and Django are the two most popular Python Web frameworks. But they were products of entirely opposite design philosophies. Django bills itself as “the Web framework for perfectionists with deadlines.” The objective of creators of Django was a framework for rapid creation of news sites and they wanted to provide every tool required for a database-backed news site development."Armin Ronacher, the creator of Flask,  clearly says that that their aim was not to build a full-stack framework like Django  but provide an extensible  minimal utility like “Trac”, which can act as an interface between the WSGI web server and the web application. So the core system was kept simple and easy to use, while the extensions for additional functionalities can be easily installed and integrate easily with the core system. For example “flask-wtforms”  is an extension  and when you install the extension , the dependency “wtforms” , a Forms library, will also be automatically installed. SQLAlchemy is an ORM in Python.

The extension “Flask-SQLAlchemy”  aims to simplify using SQLAlchemy with Flask by providing useful defaults and extra helpers that make it easier to accomplish common tasks. Flask-Migrate is an another extension that handles SQLAlchemy database migrations for Flask applications using Alembic, a migration tool associated with SqlAlchemy. If you don’t want to use Flask-migration but only Flask-SQLAlchemy you can do so. The “bottom-up” approach of Flask  is flexible enough to permit that. It is reiterated that Flask chose to provide only the minimum and not to bundle every functionality required by a web-site - database integration, a forms library, administration interface, or migration tools. You can have these through extensions that integrate well with the core. It does not mean that it is not suitable for larger applications. If you know that you need these extensions right at the beginning of your project and you don't want to set it up (or can't spare the time to), you might do better with a full-fledged MVC all-in one framework such as Django. If your database backed web app can become more complex you may opt for Flask with SqlAlchemy. For a JSON app with MongoDB, and a new “ micro-services” app  you may be  better off with Flask. For a large web application that will be maintained for some time, the  built-in admin tools and the huge community of Django is a plus point.

Object Relational Mapper(ORM)

To interact with the database we may use a driver or connector of the language provided by the database vendor. But then we have to employ database specific “SQL” to interact with it. ORM is an abstraction over the SQL layer. With an ORM, we can manipulate “objects”  to accomplish the same tasks without having to write the required lines in specific SQL.

  In other words, if you use an Object Oriented language like Python and a relational database for your app, there is paradigm mismatch between the objects in the language and the relational table. If you use an ORM it takes care of the mismatch and your code can use just “model class”- class that inherits from some Base class.  The ORM maps model class to a table and an instance to a record. The fields in the model class become columns in the table. There are two ORM patterns 1) mapper 2) wrapper. In the wrapper pattern, followed by Django’s ORM/ ActiveRecord, the model object is just a wrapper around table and no separate mapping file is used. SqlAlchemy, like Hibernate in Java, is said to follow mapper pattern. In this pattern the domain model and the relational table are to be defined separately and the configuration process should map between the two. In modern SQLAlchemy, these two tasks are usually performed together, using a system known as Declarative, which allows us to create classes that include directives to describe the actual database table they will be mapped to. The extension Flask-sqlalchemy provides a declarative base class called Model which can be used to declare models. This has actually blurred the difference between  mapper and wrapper patterns. Still there is one major difference. In ActiveRcord  pattern followed by Django each object is responsible for saving, updating and deleting itself in the database . SqlAlchemy uses a “unit of work”-similar to Hibernate in java- for database operations. We will see more of it when we the sample.

Sample
For the purpose of this article, the requirements are:

  • Flask and the “ORM” SqlAlchemy – they  come bundled with Anaconda Python Distribution
  • PostgreSQL –You should have either MySQL or PostgreSQL, open-source and production ready relational databases. PostgreSQL9.4 is used here.
  • The python driver for  PostgreSQL -“psycopg2”  
  • The extension “flask-wtf”. Both psycopg2 and “flask-wtf”  are available from Anaconda for installation. You can install them through anaconda’s package management tool “conda”,  executing “conda install package-name”
  • The extension “flask-sqlalchemy” is not available with anaconda and can be installed with general python package manager-“pip”.  Execute   “pip install flask-sqlalchemy”

Project Structure

With PyCharm IDE, create a project, say “flaskdbapp”. After choosing the interpreter 2.7.13 the Create Project wizard may look like Figure-4 given below. Create the“templates” folder within the project folder for templates file. As we don’t intent to use the migration extension, you can create a database “flaskapp” using the GUI tool “pgAdmin III”.

Html file
At first we will see the template/Html file, as it will look familiar to any web programmer. This will be the page an user will be seeing when he navigates to “localhost:5000”- we will see why when we see ‘app.py” next. In the IDE right click on “templates” folder. Choose New -?\>HTML file. The wizard may look as in Figure-1 under:

Figure-1

Give the name add_student  and Click Ok. The body of generated file may be filled up in accordance with the following .The title may also be changed. The page will look as in Figure-2 under.

When an user submits the form, the data will go through HTTPPost to the  route handler/ method “add_student()”. You can see the navigation bar of the browser changing to “localhost:5000/add_student”. We will see the code for the method when we take up “app.py”. That method is responsible for storing  the data  submitted in the form to the database. Once again when we come back to “localhost:5000” we can see all the added records. Look at the code below for the page

/templates/add­­_student.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Add_Student</title>
</head>
<body>
<h3>Students - Flask SQLAlchemy example</h3>
// form with three text fields and a button
    <form  method = "POST" action = "/add_student">    
         <label for = "name">Name</label><br>
         <input type = "text" name = "name" placeholder = "Name" /><br>
         <label for = "city">City</label><br>
         <input type = "text" name = "city" placeholder = "city" /><br>
         <label for = "dist">Dist</label><br>
         <input type= ”text” name = "dist" placeholder = "dist"/><br>
//onclick of the button, the form posts data to add_student in app.py
         <input type = "submit" value = "Submit" /> 
      </form>
// empty table for data
      <table>
         <thead>
            <tr>
               <th>Name</th>
               <th>City</th>
               <th>Dist</th>

            </tr>
         </thead>
// data from student model object is displayed
         <tbody>
            {% for student in student_list %}
               <tr>
                  <td>{{ student.name }}</td>
                  <td>{{ student.city }}</td>
                  <td>{{ student.dist }}</td>

               </tr>
            {% endfor %}
         </tbody>
      </table>
</body>
</html>

App.py
Now, We can see the file that actually runs the app . in the IDE you can choose New->Python File. After filling up the name as “app”, the wizard may look as in Figure-3 below.

The code for app.py can be filled up as under:

/flaskdbapp/app.py

from flask import Flask, request, flash, render_template # imports from core
from
flask_sqlalchemy import SQLAlchemy  # import from extensions
from flask_wtf import FlaskForm
from wtforms.ext.sqlalchemy.orm import model_form

# flask web app to which the web-server forwards the request for a dynamic page
app = Flask(__name__) 

#configuration for database connection passed to app
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres@localhost/flaskapp'
app.config['SECRET_KEY'] = "random string"

db = SQLAlchemy(app)  #-------1)

#Model class  ------1)
class Student(db.Model):
id = db.Column('student_id', db.Integer, primary_key=True)# primary key is a requirement for a model class
    name = db.Column(db.String(100)) # other fields for generation table columns
city = db.Column(db.String(50))
dist = db.Column(db.String(100))


def __init__(self, name, city, dist): # requirement of a Python Class for initializing attributes of the class/objects
    self.name = name
self.city = city
self.dist = dist

StudentForm = model_form(Student, base_class=FlaskForm) # ----2)
@app.route('/')
def index():

student_list = Student.query.all()  #  ----6)
return render_template('add_student.html',form=StudentForm, student_list=student_list)

@app.route('/add_student', methods=['POST'])
def add_student():
form = StudentForm()
student = Student()
form.populate_obj(student)
db.session.add(student)  # ------3)
db.session.commit()  
flash('Record was successfully added')
return render_template('add_student.html',)  #-----4)

if __name__ == '__main__':   #--------5)
db.create_all()
app.run(debug=True)

  1. The class SqlAlchemy from extension flask_sqlalchemy is instantiated. It used to control the SQLAlchemy integration to the Flask application. This class  provides to the Flask app access to all the SQLAlchemy functions and classes from the sqlalchemy and sqlalchemy.orm modules. So you can access the Model, the declarative base class in flask-sqlalchemy with the syntax db.Model

  2. The “model_form” object is used both to transfer data when the page submits the form and when data is sent to the page for display .

  3.  The Model class specifies which fields of the class should be mapped to which columns in the table. The lower case-name of the Model class becomes the name of the table, by default. The instance of the form is populated with a Model object. Then it is added to the unit of work-“session”. The ORM’s “handle” to the database is the session. Session will commit all changes to the database table. Till the commit() is invoked, the changes are not propagated to the database. Before the session is committed,  it can be rolled back.ie changes made to session can be reversed before it is committed.

  4. After the session commits the changes, the control should go back to the template.
  5. We have seen in the earlier article the syntax for starting the development server. The difference here is one more method has been invoked. SqlAlchemy object referred in Comment 1) invokes create_all().This method will create the table “student” from the Model class “Student”. As pointed out earlier, this blurs the difference between the mapper and wrapper patterns.As mentioned in the earlier article, the development server runs in a loop until it is stopped.

  6. In the most general sense, the session establishes all conversations with the database and represents a “holding zone” for the model objects before they are sent to the database. It also provides the entry-point to acquire a Query object, which sends queries to the database using the Session object’s current database connection, populating result rows into objects that are then stored in the Session

Run the app:

In the IDE, open the Terminal and the project appears with the prompt. You can execute “python app.py”. In the browser, you can navigate to “localhost:5000.” You can see the “/” (root url ) is mapped to index() route-hander. The handler renders the template “add_student.html”. So you will see Figure-2.When you fill up the details and submit the form,  the form is posted to “add_student” route-handler. The handler adds the data submitted in the form to populate the model object student and adds the same to the unit of work “session”. Only when the session invokes commit(), the data is stored in the database. After adding a few records you can go back to “localhost:5000” and may see Figure-5.

Conclusion

Flask being an extensible micro-framework, you can easily add required flask extensions . They say the ActiveRecord pattern in Django has some limitations to used in more complex web apps; the unit-work in SqlAlchemy is claimed to be better suited for these types of applications. For a large web app that is likely to be maintained for some-time, apart from the built-in admin and authentication tools, the huge community of Django is added attraction. We will see more about it in the next article.









Added on August 7, 2017 Comment

Comments

#1

Dominic Dommel commented on August 8, 2017 at 10:58 a.m.

Thanks for this post. I have not tried this Flask. Since it is extensible micro framework I will try this Flask app.

#2

StephanieRMontgomery commented on November 22, 2017 at 10:39 p.m.

Thanks a lot for the kind of perfect topic I have not a lot of information about it but I have got an extra unique info in your unique post.!

Post a comment