DEV Community

Muhammad Saim
Muhammad Saim

Posted on • Updated on

Flask Backend Application Setup

Hello.! I hope you are doing great. In the last post we setup our application folder structure and in this one we are setting the backend for our application.

First create .env file in the root of the folder and add our environment variables to this file.

SECRET_KEY = "abcdefgh"
FLASK_APP = run.py
FLASK_ENV= development # production/development


# Define the database
# Flask-SQLAlchemy
SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://DB_USERNAME:DB_PASSWORD@127.0.0.1:3306/DB_DATABASE"
SQLALCHEMY_TRACK_MODIFICATIONS = False

# Static Assets
STATIC_FOLDER_PATH = "/assets"
STATIC_FOLDER = "assets"
TEMPLATES_FOLDER = "views"
UPLOAD_FOLDER = "application/assets/uploads"
Enter fullscreen mode Exit fullscreen mode

Now get a detailed look on the environment variables.

SECRET_KEY
A secret key that will be used for securely signing the session cookie and can be used for any other security related needs by extensions or your application.

FLASK_APP
The FLASK_APP environment variable is used to specify how to load the application.

FLASK_DEBUG
What environment the app is running in. Flask and extensions may enable behaviors based on the environment, such as enabling debug mode.

SQLALCHEMY_DATABASE_URI
The database URI that should be used for the connection.

SQLALCHEMY_TRACK_MODIFICATIONS
If set to True, Flask-SQLAlchemy will track modifications of objects and emit signals. The default is None, which enables tracking but issues a warning that it will be disabled by default in the future. This requires extra memory and should be disabled if not needed.

STATIC_FOLDER_PATH
can be used to specify a different path for the static files on the web. Defaults to the name of the STATIC_FOLDER folder.

STATIC_FOLDER
The folder with static files that is served at STATIC_FOLDER_PATH. Relative to the application root_path or an absolute path. Defaults to 'static'.

TEMPLATES_FOLDER
The folder that contains the templates that should be used by the application. Defaults to 'templates' folder in the root path of the application.

UPLOAD_FOLDER
The folder that is responsible for our file uploads.

Now open config.py and create Config class on it and add class properties which reads data from the .env.

import os
from os import environ


class Config:
    # General Config
    SECRET_KEY = environ.get('SECRET_KEY')
    FLASK_APP = environ.get('FLASK_APP')
    FLASK_DEBUG = environ.get('FLASK_DEBUG')

    BASE_DIR = os.path.abspath(os.path.dirname(__file__))

    # Static Assets
    STATIC_FOLDER_PATH = environ.get('STATIC_FOLDER_PATH')
    STATIC_FOLDER = environ.get('STATIC_FOLDER')
    TEMPLATES_FOLDER = environ.get('TEMPLATES_FOLDER')
    UPLOAD_FOLDER = environ.get('UPLOAD_FOLDER')

    # Flask-SQLAlchemy
    SQLALCHEMY_DATABASE_URI = environ.get('SQLALCHEMY_DATABASE_URI')
    SQLALCHEMY_TRACK_MODIFICATIONS = bool(environ.get('SQLALCHEMY_TRACK_MODIFICATIONS'))
Enter fullscreen mode Exit fullscreen mode

So in the config.py BASE_DIR is use to store the root path of the application folder for use in the future.

Now open application/init.py file and start the configuring application. First import the required modules.

from dotenv import load_dotenv
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
Enter fullscreen mode Exit fullscreen mode

after that load the ENV variables

load_dotenv()
Enter fullscreen mode Exit fullscreen mode

Now set the database constraints names for forigen keys, primary keys and other constrants. Make a dictionary of python.

convention = {
    "ix": 'ix_%(column_0_label)s',
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(column_0_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
}
metadata = MetaData(naming_convention=convention)
Enter fullscreen mode Exit fullscreen mode

After that initialize the SQLAlchemy and the Migrate objects.

db = SQLAlchemy(metadata=metadata)
migrate = Migrate()
Enter fullscreen mode Exit fullscreen mode

So at this time our init.py file looks like this.

from dotenv import load_dotenv
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData
from flask_debugtoolbar import DebugToolbarExtension

load_dotenv()

convention = {
    "ix": 'ix_%(column_0_label)s',
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(column_0_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
}
metadata = MetaData(naming_convention=convention)

db = SQLAlchemy(metadata=metadata)
migrate = Migrate()
Enter fullscreen mode Exit fullscreen mode

Now open a application/settings.py file and import the moduels.

from flask import Flask
import os

import config
from application import (
    db,
    migrate
)
Enter fullscreen mode Exit fullscreen mode

So we create init.py in our application folder so this will make application a python package so in the last we use from statement with application and which db or migrate objects we created in the init.py so we are now importing from the applictaion.

Create a home.py file in our controllers folder and use flask blueprint to create a blueprint for our first route.

from flask import Blueprint, render_template

controller = Blueprint('home', __name__)

@controller.route('/', methods=['GET'])
def index():
    return "Home Controller"
Enter fullscreen mode Exit fullscreen mode

Now Create a user.py file in models folder to create our first model. This will be SQLAlchemy model and also uses for our migartions also.

User class will be extend with db.Model and here we have a special property name __ tablename __ which is use to change the tablename otherwise without __ tablename __ table name will be the class name.

from application import db


class User(db.Model):

    __tablename__ = 'users'

    id = db.Column(
        db.Integer,
        primary_key=True
    )

    name = db.Column(
        db.String(255),
        nullable=False
    )

    email = db.Column(
        db.String(255),
        unique=True,
        nullable=False
    )

    password = db.Column(
        db.String(255),
        nullable=False
    )

    role = db.Column(
        db.String(50),
        nullable=False,
        server_default="user"
    )

    created_at = db.Column(
        db.DateTime,
        server_default=db.func.now(),
        nullable=False
    )

    updated_at = db.Column(
        db.DateTime,
        server_default=db.func.now(),
        nullable=False
    )

Enter fullscreen mode Exit fullscreen mode

So Now we have our controller and the model so we can now register those in our applciation.

Now open settings.py and create three functions in the file first one will be the register_blueprints, import_models and initialize_plugins.

In the register_blueprints function import the controller from the controllers and register that controller.

def register_blueprints(app):
    from application.controllers import (
        home
    )

    app.register_blueprint(home.controller)
Enter fullscreen mode Exit fullscreen mode

In the import_models function import the models from the Models and register them in this function.

def import_models():
    # import database models
    from application.models import (
        user
    )
Enter fullscreen mode Exit fullscreen mode

Last but not least we have a initialize_plugins which is used for initialize the flask apps to the flask like SQLAlchemy, Flask Migrate etc.

Now its time to create the our last function in this file which will be the initialize_flask_app which is responsible to initialize the flask app with configurations which we added in our config.py.

def initialize_flask_app():
    # Initialize the core application.
    app = Flask(
        __name__,
        instance_relative_config=False,
        template_folder=config.Config.TEMPLATES_FOLDER,
        static_folder=config.Config.STATIC_FOLDER,
        static_url_path=config.Config.STATIC_FOLDER_PATH
    )
    app.config.from_object('config.Config')
    return app
Enter fullscreen mode Exit fullscreen mode

instance_relative_config
if set to True relative filenames for loading the config are assumed to be relative to the instance path instead of the application root.

So here I set it to False so we can load our own configs from our own location so at the 2nd last line we set flask app object and read data from the object so we use from_object function from our config file.

So our settings.py will look like this.

def initialize_plugins(app):
    # Initialize Plugins
    db.init_app(app)
    migrate.init_app(app, db)
Enter fullscreen mode Exit fullscreen mode

So at this moment our settings.py will look like this.

from flask import Flask
import os

import config
from application import (
    db,
    migrate
)


def register_blueprints(app):
    from application.controllers import (
        home
    )

    app.register_blueprint(home.controller)


def initialize_plugins(app):
    # Initialize Plugins
    db.init_app(app)
    migrate.init_app(app, db)


def import_models():
    # import database models
    from application.models import (
        user
    )

def initialize_flask_app():
    # Initialize the core application.
    app = Flask(
        __name__,
        instance_relative_config=False,
        template_folder=config.Config.TEMPLATES_FOLDER,
        static_folder=config.Config.STATIC_FOLDER,
        static_url_path=config.Config.STATIC_FOLDER_PATH
    )
    app.config.from_object('config.Config')
    return app
Enter fullscreen mode Exit fullscreen mode

Now open init.py file and create create_app function at the end of the file.

def create_app():
    from application.settings import (
        initialize_flask_app,
        initialize_plugins,
        import_models,
        register_blueprints
    )
    app = initialize_flask_app()

    with app.app_context():
        # initialize plugins
        initialize_plugins(app)

        # register blueprints
        register_blueprints(app)

        # import models
        import_models()

        return app
Enter fullscreen mode Exit fullscreen mode

After this function our init.py will look like this.

from dotenv import load_dotenv
from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy import MetaData

load_dotenv()

convention = {
    "ix": 'ix_%(column_0_label)s',
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(column_0_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s"
}
metadata = MetaData(naming_convention=convention)

db = SQLAlchemy(metadata=metadata)
migrate = Migrate()


def create_app():
    from application.settings import (
        initialize_flask_app,
        initialize_plugins,
        import_models,
        register_blueprints
    )
    app = initialize_flask_app()

    with app.app_context():
        # initialize plugins
        initialize_plugins(app)

        # register blueprints
        register_blueprints(app)

        # import models
        import_models()

        return app

Enter fullscreen mode Exit fullscreen mode

firstly import all the functions from the settings.py file. initialize the flask app and set to the app variable.

Now we use app_context() to initialize all the functions which we imported from the settings.py and after that return the app obejct.

Now its time to add some code to our run.py to boot our applictaion.

from application import create_app

app = create_app()

if __name__ == '__main__':
    app.run(host='0.0.0.0')
Enter fullscreen mode Exit fullscreen mode

Simple import create_app function which we created in our init.py file and get call the function to get the flask object and with run method boot our application.

Now create a Database I cretaed the Database with the name of python_flask_blog.

image

and set your Database credentials in your .env file.

SQLALCHEMY_DATABASE_URI = "mysql+mysqlconnector://muhammadsaim:muhammadsaim@127.0.0.1:3306/python_flask_blog"
Enter fullscreen mode Exit fullscreen mode

Now in your terminal initiate the flask migrate run this commad.

flask db init
Enter fullscreen mode Exit fullscreen mode

This will create some migartion related configuration files in migartions folder which we created on the root folder.

image

Create a migration by running this command.

flask db migrate -m "Create User table."
Enter fullscreen mode Exit fullscreen mode

This will create a file migartion version file to keep track of the changes so we can rollback to our migrations.

image

So we commit the migrations now run this command to push this commit to the Database this will cretae the users table.

flask db upgrade
Enter fullscreen mode Exit fullscreen mode

image

And after that our table is created.

image

We have two tables 1st one is alembic_version and the other is users which we created but the first one is used by the migration to track the record of the migration.

Now finaly its time to run our Application for this we have to run this command.

python run.py
Enter fullscreen mode Exit fullscreen mode

This command will open server and give us the url where our application will be served from our development server.

image

Open your browser and open this link on the broswer and we get the our index route which we cretaed in our home controller after opening this we have a page with written on this Home Controller

image

Hurray now we have our applictaion up.

You can get the updated code on GitHub Repo

Thanks for being with me.

See you guys in next post if you have any issue while going with this post feel free to comment.

Top comments (0)