Open In App

Declaring Models in Flask

Last Updated : 13 Dec, 2023
Improve
Improve
Like Article
Like
Save
Share
Report

Models are used in Flask to conveniently handle interactions with databases (like SQL, SQLite, etc.) using ORM (Object Relational Mapping). This article describes what is ORM, how to declare models in Flask, and finally a simple example Flask application. It assumes basic familiarity with Flask and Python programming languages.

What is ORM in Python Flask?

ORM (Object Relational Mapping) is a programming technique which lets the programmer to write code using the Object-Oriented features of a language to interact with a database.

This abstracts away the details of the database language and makes the job easier for the programmer. Models are used in Flask to achieve Object Relational Mapping and thus help the programmer to interact with the database using Python’s object-oriented features such as classes and methods.

Declaring Models in Flask

The Flask community provides the “Flask-SQL Alchemy” library/extension which is the go-to library for declaring models in Flask. It is a wrapper around the “SQL Alchemy” library with added capabilities to handle the details related to responses and requests so that you don’t have to worry about that. Before proceeding any further, we need to have the following installations –

Installations required

Flask doesn’t support ORM, but with the help of flask-sqlalchemy, we can achieve the ORM functionalities. Once Python is installed, we can use a package manager such as pip to install the rest with this command:

pip install flask-sqlalchemy

Declaring Models in Flask with Flask-SQL Alchemy

This section contains the step-by-step explanation of the code. After doing the necessary imports, we define the create_app function which returns the flask app (the app-factory method of creating flask apps). We create the app and define everything inside this function since this app is small. If it is large, then in-practice, one would generally create multi-file definitions and then add them to the app inside this function by using flask features such as blueprints. Here is the explanation of the code inside this function –

Step 1: Creating flask app

First we create the flask app with the line

app = Flask(__name__, ...)

as usual and do the configurations with app.config… .

Python3




app = Flask(__name__, instance_relative_config=True)
app.config.from_pyfile('config.py', silent=True)
app.config.from_mapping(SECRET_KEY='dev')


Step 2: Creating the instance folder

Instance folder is where our SQL Lite database will be saved. The path to the instance folder is accessed through app.instance_path (Note: the instance path is defined in configurations and can be altered from there if one wants). Then we try to create the instance folder with os.makedirs method. If it already exists, OSError will be raised. We catch the error and do nothing in this case because the folder already exists if error occurs.

Python3




try:
    os.makedirs(app.instance_path)
except OSError:
    pass


Step 3: Configure the database location

Next we need to specify flask where to find the database in configurations. For SQL Lite, we need to tell the path of the database file relative to the path to instance folder preceded by “sqllite:///” string. This is done with the line “app.config[“SQLALCHEMY_DATABASE_URI”] = …” LINE. Remember this file doesn’t need to exist yet.

Python3




app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///event_database.db"


Step 4: Creating the database object (db)

Define the Base class inheriting “DeclarativeBase” (this can be altered if you want some different model other than delclarative base by modifiying this class”). Next we create the database object using SQLAlchemy and passing this Base class to it and store it in “db”. Next, we initiate db with the app using “db.init_app(app)” line.

Python3




class Base(DeclarativeBase):
    pass
 
db = SQLAlchemy(model_class=Base)
db.init_app(app)


Step 5: Declaring the model(s)

Now we begin to define the models. A model defines what data elements/rows of the database contain. A model must inherit the db.Model class where db is our database object as defined in last step. Each of the attribute is defined as a class variable in this class (like date and event here) and is assigned the type of data it contains. We define the date to be the primary key. This is SQL Alchemy syntax and one needs to refer to its documentation to get more details.

Our model here is Event which contains the attributes date and event (containing event description).

Python3




class Event(db.Model):
    date = mapped_column(db.String, primary_key=True)
    event = mapped_column(db.String)


Step 6: Creating the database

Now we need to define the database to store the data for our model(s). This is done by calling the “db.create_all()” method. This creates the necessary tables and the database files to represent all the models defined by inheriting “db.Model” class.

Since we don’t need to call this function always, we create a command named ‘init-db’ using the click library and register it with the flask app using “app.cli.add_command” function and passing it the function. Once registered, we can call this command hence call the “db.create_all()” function only when we want using the command just like the flask run

flask --app eventLog init-db

Once we call this command, our database file and database is ready to handle data for our model(s).

Python3




@click.command('init-db')
def init_db_command():
    with app.app_context():
        db.create_all()
        click.echo('Database created successfully')
 
app.cli.add_command(init_db_command)


Step 7: Use the SQL Alchemy syntax to query the database

With everything ready here, we can query the database using SQL Alchemy syntax from db.session object. For example, here we define a home page querying the database at two places depending upon the request type. When it receives a GET request, it returns an HTML page containing table of all the events. For this we query the database to receive all the events using –

db.session.execute(db.select(Event).order_by(Event.date)).scalars()

and pass it to the rendering template. This query returns an iterable of Event class (or Event model) objects. So if e is an element in this list of iterables, we can access date using e.date and event description using e.event which are the attributes of our model. This is done in the template.

Python3




@app.route('/', methods=['GET', 'POST'])
    def home():
        if(request.method == 'POST'):
            db.session.add(Event(date=datetime.datetime.now(
            ).__str__(), event=request.form['eventBox']))
            db.session.commit()
            return redirect(url_for('home'))
        return render_template('home.html', eventsList=db.session.execute(db.select(Event).order_by(Event.date)).scalars())
 
    return app


Similarly, homepage can receive a POST request to add an event. In this case we receive the event details from the form and execute a query to add the event with the current date and time and the provided description to the database. For this, we use “db.session.add” and pass it an instance of our Event model/class containing the information. Finally, call “db.session.commit()” to commit the changes i.e., the addition here.

Flask app using Models

We create a simple flask app named “eventLog” where you can see and add events. The date and time are added automatically when the event is added. It just contains a single home page.

File structure

rootFolder
|_ eventLog
    |_templates
    |   |_ home.html
    |_ __init__.py

__init__.py File

This is a Flask web application with a SQLite database for managing events. It defines a “create_app” function setting up the Flask app, SQLAlchemy for database handling, and a simple “Event” model. The code includes a route for rendering and handling form submissions on the home page to add events to the database. Additionally, it has a CLI command “init-db” to initialize the database.

Python3




from flask import Flask, redirect, url_for, render_template, request
import os
import datetime
 
import click
 
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
 
def create_app(test_config=None):
    # a simple page that says hello
    app = Flask(__name__, instance_relative_config=True)
 
    app.config.from_pyfile('config.py', silent=True)
    app.config.from_mapping(SECRET_KEY='dev')
 
    # ensure instance folder exists
    try:
        os.makedirs(app.instance_path)
    except OSError:
        pass
 
    # configure the path to SQLite database, relative to the app instance folder
    app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///event_database.db"
 
    class Base(DeclarativeBase):
        pass
 
    # create the database object and initiate it
    db = SQLAlchemy(model_class=Base)
    db.init_app(app)
 
    # defining model for event
    class Event(db.Model):
        date = mapped_column(db.String, primary_key=True)
        event = mapped_column(db.String)
 
    @click.command('init-db')
    def init_db_command():
        ''' command for initiating the database '''
        with app.app_context():
            db.create_all()
            click.echo('Database created successfully')
 
    app.cli.add_command(init_db_command)
 
    @app.route('/', methods=['GET', 'POST'])
    def home():
        if(request.method == 'POST'):
            db.session.add(Event(date=datetime.datetime.now(
            ).__str__(), event=request.form['eventBox']))
            db.session.commit()
            return redirect(url_for('home'))
        return render_template('home.html', eventsList=db.session.execute(db.select(Event).order_by(Event.date)).scalars())
 
    return app


home.html Jinja Template

This HTML code defines a simple webpage displaying an event log with a table showing date-time and event details. It uses Jinja2 templating to iterate through a list of events passed from the Flask app and dynamically populate the table rows. The page also includes a form to add new events, with a text input and a submit button. Additionally, it links to an external stylesheet named “style.css” for styling.

HTML




<html>
    <head>
        <title>EventLog</title>
        <link rel = 'stylesheet' href = {{url_for('static', filename='style.css')}}/>
    </head>
    <body>
        <table>
            <tr>
                <th>Date & Time</th>
                <th>Event Details</th>
            </tr>
        {%-for row in eventsList-%}
            <tr>
                <td>{{row.date}}</td>
                <td>{{row.event}}</td>
            </tr>
        {%-endfor-%}
        </table>
        <hr/>
        <form method="post">
            <title>Add event</title>
            <label for="eventBox">Event Description</label>
            <input name="eventBox" id="eventBox" required/>
            <input type="submit" value = "Add">
        </form>
    </body>
</html>


Output

Models in Flask

A simple flask app “eventLog” running on browser. Uses Flask Models for managing database.

Running the app

First run the following command from the rootFolder to initiate the database –

flask --app eventLog init-db

Once done, run the flask app using the command –

flask --app eventLog run --debug

This will start the app in debug mode at local host port 5000. Visit the following URL in browser –

http://127.0.0.1:5000/

Video Output

Flask Model

Conclusion

In this article, we saw what object-relational mapping (ORM) is and then what are models in flask and how to declare them using Flask-SQL Alchemy. Declaring models is a way to implement ORM style of working with database which abstracts away the details of the underlying database system thus allowing the programmer to code easily using object-oriented features and use different databases without having to do any significant changes in the code. Finally, we presented an example flask app named “eventLog” which demonstrates declaring models with flask.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads