Using Blueprint to Organize Flask Apps
Tags: flask, python, programming, tutorial
Published: 2023-11-26 17:03:19

## Introduction

Large applications can become complex and difficult to manage due to the presence of numerous components and intricate structures.

Flask blueprints help in organizing large applications into smaller, manageable components, leading to enhanced maintainability of the application.

Blueprints can contain views, templates, and static files for various components, similar to the structure of a typical Flask application. These blueprints can be registered with the Flask app to integrate them into the application.

## Flask App Structure

If you've used the Flask framework before, you might structure your Flask application as follows:

```plaintext
.
├── app.py
├── static/
└── templates/
    └── index.html
```

After you've created the structure for your app, you'll add some code to the `app.py` file.

```python
# app.py
from flask import Flask, render_template

app = Flask(__name__)

@app.route("/")
def home():
    return render_template("index.html")
```

In smaller projects, defining views within the main file may not pose a significant problem. However, in more complex projects, when you need to create routes for various components such as user management, admin functions, profiles, voting, and more, organizing these routes within a single file can become challenging. This can lead to poor code maintainability and make the project harder to manage.

This is precisely where blueprints prove valuable, as they allow you to structure your application into smaller components, enhancing maintainability.

## Creating the Blueprint

Add the following code to a new Python file at the root level, `blueprint.py`.

```python
# blueprint.py
from flask import Blueprint

bp = Blueprint("blueprint", __name__)

@bp.route("/")
def home():
    return "<h1>Hello</h1>"

@bp.route("/user")
def user_info():
    return "<h1>User Info</h1>"
```

The code imports the `Blueprint` class from the `flask` which will help in defining the routes.

The instance of the `Blueprint` is created by calling `Blueprint("blueprint", __name__)` and passed in two arguments, first, `"blueprint"`, is the Blueprint's name, and the second, `__name__`, is the Blueprint's import name. After that, the instance is saved in the `bp` variable.

The routes are defined using the Blueprint instance (`bp`) in a similar manner to how routes are defined using the Flask application instance (`app`).

The `@bp.route()` decorators are used to associate URL routes with the view functions defined within the blueprint. The `home()` function is associated with the root URL (`"/"`), and the `user_info()` function is associated with the `"/user"` URL.

## Registering the Blueprint

A blueprint is similar to a Flask app, but it is not an app, instead, the blueprint must be registered within the Flask app to extend its functionality.

Navigate to the main Flask app created in the `app.py` Python file and register the above-created blueprint.

```python
# app.py
from flask import Flask
from blueprint import bp

# Flask app instance
app = Flask(__name__)

app.register_blueprint(bp)

if __name__ == "__main__":
    app.run(debug=True)
```

The code imports the Blueprint instance, `bp`, from the `blueprint` module (`blueprint.py`), and this import includes all of the blueprint's routes and views.

The `register_blueprint()` method is then used to register the blueprint instance (`bp`) with the Flask app instance (`app`).

If you run the app, you can access the routes defined within the blueprint.

## Mounting Blueprints at Different Locations

Blueprints can be attached to a certain URL path that can be prefixed with all of the routes defined within the blueprint.

You can make this happen by using the `url_prefix` parameter while registering the blueprint using the `register_blueprint()` method in the Flask app.

```python
# app.py
from flask import Flask
from blueprint import bp

# Flask app instance
app = Flask(__name__)

app.register_blueprint(bp, url_prefix="/demo")

if __name__ == "__main__":
    app.run(debug=True)
```

The `url_prefix` is now `"/demo"`. This means that the routes within the blueprint (`"/"` and `"/user"`) can be accessed by adding `"/demo"` at the beginning of their URL paths.

The complete URL of the (`"/"`) route is changed to `"/demo/"` for the `home()` function. Also, the complete URL of the `"/user"` route will now be `"/demo/user"` for the `user_info()` function.

You can set the `url_prefix` while making the Blueprint instance. The Blueprint class offers a `url_prefix` parameter, and the provided code example demonstrates its usage.

```python
# blueprint.py
from flask import Blueprint

bp = Blueprint("blueprint", __name__, url_prefix="/sample")
```

The URL path for the (`"/"`) route will become `"/sample/"`. Likewise, the URL path for the `"/user"` route will change to `"/sample/user"`.

**Note:** If you set the `url_prefix` parameter inside the blueprint, avoid setting it again during the blueprint registration. Doing so will overwrite the blueprint's URL prefix.

> Caution:
> 
> If you set url\_prefix in the blueprint and then set it again while registering the blueprint within the app, the latter will overwrite the former.

## Templates and Static Folders

You have several options for organizing your app using blueprints.

```plaintext
.
└── app/
    ├── __init__.py
    ├── admin/
    │   ├── __init__.py
    │   ├── routes.py
    │   ├── static/
    │   └── templates/
    ├── user/
    │   ├── __init__.py
    │   ├── routes.py
    │   ├── static/
    │   └── templates/
    └── models.py
```

If your project's structure aligns with the example above, you'll have to indicate the locations of **templates** and **static** folders within your `Blueprint`.

The `Blueprint` class gives you parameters, `templates_folder` and `static_folder`, which allow you to define the exact path (either absolute or relative) to the blueprint's templates and static folder when creating an instance of the `Blueprint` class.

```python
# admin/routes.py
from flask import Blueprint

admin_bp = Blueprint("admin_blueprint",
                     __name__,
                     template_folder="templates",
                     static_folder="static")
```

```python
# user/routes.py
from flask import Blueprint

user_bp = Blueprint("user_blueprint",
                    __name__,
                    template_folder="templates",
                    static_folder="static")
```

Both `"admin_bp"` and `"user_bp"` blueprints have their own directories for templates and static files. This separation ensures that their respective templates and assets are kept separate from other parts of the app, maintaining isolation and organization.

## Avoid Template Name Clashes

When you're designing blueprints for different parts of your application, the arrangement of your project holds significance. For instance, referring to the layout mentioned above, duplicating HTML filenames in the admin/templates and user/templates directories can lead to naming clashes.

The Flask application searches for templates in the `"templates"` directory. If there are duplicate template file paths across different blueprints, the one that takes precedence depends on the order of blueprint registration. The one registered later will override the earlier one.

To avoid potential issues, you can shape the project layout in the following manner:

```plaintext
.
└── app/
    ├── app.py
    ├── models.py
    ├── admin/
    │   ├── __init__.py
    │   ├── routes.py
    │   ├── static/
    │   └── templates/
    │       └── admin/
    │           └── index.html
    └── user/
        ├── __init__.py
        ├── routes.py
        ├── static/
        └── templates/
            └── user/
                └── index.html
```

Alternatively, you can assign distinct names to the templates.

## Template Routing with Blueprints

Template routing with blueprints is distinct from the conventional approach. It involves a specific format where the blueprint name is added as a prefix to the associated view function.

As an example, if your blueprint is named `admin_blueprint` and includes a view function named `home()`, then the format becomes `admin_blueprint.home`.

**admin/templates/admin/index.html**

```xml
<a href="{{ url_for('user_blueprint.home') }}">User</a>
```

The link mentioned above points to the route connected with the `home()` function in the `user_blueprint`. The `url_for()` function dynamically produces a URL for the `user_blueprint.home` route.

**user/templates/user/index.html**

```xml
<a href="{{ url_for('admin_blueprint.home') }}">Admin</a>
```

Likewise, the situation is identical to the link mentioned earlier. It leads to the route linked with the `home` function in the `admin_blueprint`. The `url_for()` function dynamically generates a URL for the `admin_blueprint.home` route.

## Including CSS Files with Blueprints: Creating URLs for Static Assets

The procedure is quite similar to what you did with templates. To include or provide CSS files within the HTML template, you should construct a URL that directs to the CSS file situated in the specified static folder of the blueprint.

As an example, the method to link the `"style.css"` file found in the `static` directory of the `"admin_blueprint"` blueprint would be `url_for('admin_blueprint.static', filename='style.css')`.

Note: You must indicate the directory path where static files (CSS, JavaScript, images, etc.) are situated for this blueprint. This is achieved using the `static_folder` parameter.

**admin/templates/admin/index.html**

```xml
<link rel="stylesheet" href="{{ url_for('admin_blueprint.static', filename='style.css') }}">
```

This HTML code snippet above uses the `url_for()` function to generate a URL that points to the **"style.css"** static file linked to the `admin_blueprint`.

## Custom URL Path for Static Files

Flask Blueprint provides a `static_url_path` parameter that provides flexibility to define a custom URL prefix for the static files (CSS, JavaScript, images, etc.) associated with the `Blueprint`.

```python
# admin/routes.py
from flask import Blueprint

admin_bp = Blueprint("admin_blueprint",
                     __name__,
                     template_folder="templates",
                     static_folder='static',
                     static_url_path='admin')
```

The `static_url_path` is established as `"admin"`, effectively making the static files within the `admin_blueprint` accessible under the `admin/` URL path.

Now you can directly include static files (CSS, JavaScript, images, etc) by specifying the static URL path.

### Including Static Files using Static URL Path

```xml
<link rel="stylesheet" href="admin/style.css">

<!--Body Section-->
<img src="admin/partners.png">
```

The complete webpage would look like the image shown below:


![Webpage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/47ewgs47omt5kq1mo7yo.png)

## Conclusion

A Flask Blueprint is used as an extension for a Flask app, and it serves the purpose of organizing large and complex applications into smaller, more manageable components.

Let's recall what you've seen in this tutorial:

* What is Blueprint in Flask
    
* Creating and Registering a Blueprint
    
* Template routing with Blueprint
    
* Including static files with Blueprint
    
* Custom URL path for static assets
    

---

🏆**Other articles you might be interested in if you liked this one**

✅[Upload and display images on the frontend using Flask in Python](https://geekpython.in/render-images-from-flask).

✅[Building a Flask image recognition webapp using a deep learning model](https://geekpython.in/flask-app-for-image-recognition).

✅[How to connect the SQLite database with Flask app using Python](https://geekpython.in/connect-sqlite-database-with-flask-app)?

✅[How to create a database in Appwrite using Python](https://geekpython.in/database-in-appwrite-using-python)?

✅[How to Integrate TailwindCSS with Flask](https://geekpython.in/merging-tailwindcss-into-flask-apps)?

✅[What is context manager and how to use them using with statement](https://geekpython.in/context-managers-and-python-with-statement)?

---

**That's all for now**

**Keep Coding✌✌**