Python Web Development With Flask - Part 6

in STEMGeeks3 months ago

Using Flask Blueprints

Welcome back to another article on getting started with coding Python. If you haven't been following along that's fine cause we will show you all the code to get catch up before we get stuck into this articles main subject.

Our past five articles have been all about web development, specifically using the Flask web development framework. In this article we are going to introduce using blueprints as part of your Flask web application. Blueprints are something we haven't mentioned previously and are a way in which we can organize and separate different parts of our code to make it easier to read and work with. Each blueprint we create in our application will be a distinct component of our application and should also encapsulate a significant piece of functionality.

We will need to import the Blueprints module as part of our code to start using them but the basic structure of using them is simple segregating each component by the application directory structure.

For example it is recommended that the directory structure be set up like the structure below:

  • projects/<blueprint_name>/templates/<blueprint_name/>

As you'll see in the following code section we will create a blueprint specifically for user management and that will be the name of our blueprint as well.

Within the blueprint directory we can then include the Python source code and templates specific for that functionality.

It is recommended though that all static files like CSS, images and the base templates remain with the Flask application.

Back To The Flasking Application


We have developing our flashing application over the past few articles and have got it to a point where we can refactor the code into two distinct Blueprints. Once for our runs and one for our user functionality.

If you would like to revert back to the previous articles, head over to our GitHub page where you will find all the code as well as links to all the other articles in the series:
https://github.com/vincesesto/python_study

If you've been following along so far with this project, you will not have to perform the following steps, but if you are new to the series, run the following set of commands in your working directory to get the "Flasking" web app up and running before we move further on with this project:

# Clone the repository:
git clone https://github.com/vincesesto/python_study.git

# Move into the root directory:
cd article_17/

# Create a virtual environment named venv
python3 -m venv venv

# Activate the virtual environment
source venv/bin/activate

# Install all of the requirements:
pip3 install -r requirements.txt

# Export where the app.py script is
export FLASK_APP = "app.py"

# Verify the flask web server runs without errors
flask run

# Open a web browser and enter the following 
# URL to see the index page of the Flasking app
http://127.0.0.1:5000/

Everyone should now be on the same page and we can get started working with static files.

Currently the directory structure of our application looks like the following where we have most of our code in the root of the app with static, templates and tests directories all created in there as well.

├── app.py
├── requirements.txt
├── static
├── templates
├── tests

To separate our code into blueprints we are going to move our directory structure to look similar to the one below. Where we will create a separate projects directory and have a runs and users blueprints directory created in there.

├── app.py
├── project
│   ├── __init__.py
│   ├── runs
│   │   ├── __init__.py
│   │   ├── routes.py
│   │   └── templates
│   │       └── runs
│   └── users
│       ├── __init__.py
│       ├── routes.py
│       └── templates
│           └── users
├── requirements.txt
├── static
├── templates
│   └── base.html
├── tests

Set Up The Runs Blue Prints


We will start with the runs blueprint, so access your working environment again and start with the set up of the code.

Start by creating the project and runs directories with the follow command:

mkdir -p projects/runs

We need to create a blank init.py file in the base of the projects directory and we will create this now before we forget:

touch projects/__init__.py

Now create the same file in the project/runs directory. This file will specify the locations of our routes and templates for that blueprint:

touch projects/runs/__init__.py

We first want to specify the name of the blueprint ('runs') and it specifies the location of the template files within the blueprint. Additionally, the last line imports the routes that we'll create in routes.py.

"""
This blueprint allows for users to add, edit, and delete
run data from their application.
"""
from flask import Blueprint

runs_blueprint = Blueprint('runs', __name__, template_folder='templates')

from . import routes

We can now create the routes specific for this blueprint which will now hold all of the runs specific routes that contained in our original app.py script. Start by creating the new routes.py file in the runs blueprint:

touch projects/runs/routes.py

Add the following code below and it should all look fairly familiar to you. Make note though there are some subtle changes where we use the redirect() and render_template() functions. They now have the "runs" added to the front of the path so the routes know to use the blueprint when presenting those pages to the user:

from flask import Flask, render_template, request, session, redirect, url_for
from . import runs_blueprint
from flask import current_app

app = Flask(__name__)

@runs_blueprint.route('/add_run', methods=['GET', 'POST'])
def add_run():
    if request.method == 'POST':
        for key, value in request.form.items():
            print(f'{key}: {value}')

        # Save the form data to the session object
        session['type_of_run'] = request.form['type_of_run']
        session['number_of_kilometres'] = request.form['number_of_kilometres']
        session['comments'] = request.form['comments']
        return redirect(url_for('runs.list_runs'))

    return render_template('runs/add_run.html')

@runs_blueprint.route('/runs')
def list_runs():
    return render_template('runs/runs.html')

Because we have used a base template for our app, none of the blueprints templates need to be changed, but the location where they are found need to be. We now need to set up a templates directory specific for this blueprint as we have below:

mkdir -p projects/runs/templates/runs/

And now move the templates from the origin templates directory to the blueprints directory:

mv templates/add_run.html  projects/runs/templates/runs/

mv templates/runs.html  projects/runs/templates/runs/

And Now The Users Blueprint


The users blueprint is pretty similar to the way we set up the runs. It is a matter of refactoring the code to match so we will limit the discussion and present the code below:

First create the directory for the project:

mkdir projects/users

And create the init.py file to set up the blueprint:

touch projects/users/__init__.py

Open the file with your text editor and add in the following code:

"""
This Blueprint allows for new users to register and for
users to log in and to log out of the application.
"""
from flask import Blueprint

users_blueprint = Blueprint('users', __name__, template_folder='templates')

from . import routes

Create the routes.py file for the users blueprint:

touch project/users/routes.py

Open the file with your text editor and add in the following code:

from flask import Flask, render_template, request, session, redirect, url_for, flash
from . import users_blueprint

app = Flask(__name__)

@users_blueprint.route('/')
def index():
    return render_template('users/index.html')

@users_blueprint.route('/about')
def about():
    return render_template('users/about.html', version='0.0.1')

Create the new directory for the users templates. As we did earlier we only need to copy them across to the blueprints directory:

mkdir -p projects/users/templates/users

And now copy them across

mv templates/about.html projects/users/templates/users/

mv templates/index.html projects/users/templates/users/

Bringing It All Together


We've made a few changes to our code to refactor the users and runs functionality into their own blueprint. We need to now tell our app.py file so it will know where to file all of the routes and code to then display the correct data to the user.

Open the app.py file with your text editor and we can now remove all of the routes that are currently listed as the have been moved to their respective blueprints. All we now need to include is the code below where we have imported the runs_blueprints and the users_blueprints. The last two lines of the file they use the register_blueprints() function to then use the imported blueprints:

from flask import Flask, render_template, request, session, redirect, url_for

app = Flask(__name__)

app.secret_key = '\x98)\x861hX[\xf1\xc5Z\[email protected]\xe7[K\xfe\xb5\xc7~\xb0\x99\x1e\x8f\xfem\xa6F\xc1&'

# Import the blueprints
from projects.runs import runs_blueprint
from projects.users import users_blueprint

# Register the blueprints
app.register_blueprint(runs_blueprint)
app.register_blueprint(users_blueprint, url_prefix='/users')

As you can see though, we have also added a url_prefix for the users. This means that the about.html file and the index.html file will need to have the /users/ path amended to the url for it to function correctly.

Flask also gives us a way to display all our routes using the "flask routes" command to display all of the routes currently set up in our project. If the app.py file and our blueprints are set up correctly, you should see something similar to the output below:

$ flask routes

Endpoint        Methods    Rule
--------------  ---------  -----------------------
runs.add_run    GET, POST  /add_run
runs.index      GET        /
runs.list_runs  GET        /runs
static          GET        /static/<path:filename>
users.about     GET        /users/about
users.index     GET        /users/

The only thing we have left to do is update the base template as it will be pointing to the old files. Open the templates/base.html file with your text editor and the only lines we need to change is where we have our links to the Home, List and Add Runs pages. The href now needs to reference the relevant blueprint for each of the links as we have in the code below:

          <li class="nav-item"><a class="nav-link" href="{{ url_for('users.index') }}">Flasking Home</a></li>
          <li class="nav-item"><a class="nav-link" href="{{ url_for('runs.list_runs') }}">List Runs</a></li>
          <li class="nav-item"><a class="nav-link" href="{{ url_for('runs.add_run') }}">Add Runs</a></li>

The complete file is located at the following link:
https://raw.githubusercontent.com/vincesesto/python_study/main/article_18/templates/base.html

All you now need to do is use the "flask run" command from the command line to run the development server and verify all is now working fine. You should now be able to run the app as you did previously but now it is refactored into blueprints within the directory structure.

Found this post useful? Kindly tap the up vote button below! :)

About The Author

I am a DevOps Engineer, Endurance Athlete and Author. As a DevOps Engineer I specialize in Linux and Open Source Applications. Particularly interested in Search Marketing and Analytic’s, and is currently developing my skills in devops, continuous integration, security, and development(Python).

Posted with STEMGeeks