Structuring a Flask Project
source link: http://www.patricksoftwareblog.com/structuring-a-flask-project/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Introduction
Flask provides such great flexibility when developing a web application, including the structure of the application. Flask applications can range from a single file to larger projects with multiple Blueprints. In this blog post, I’m going to describe how I like to structure a Flask application using Blueprints and an Application Factory function.
For reference, the project that I created as part of writing this blog post is available on GitLab: Flask User Management Example.
Blueprints
Blueprints allow you to cleanly organize the source code of your Flask application. Each Blueprint encapsulates a significant piece of functionality in your application. For example, I like to have a separate Blueprint for handling the user management of a Flask application.
I like to create a separate package (ie. a directory that includes the __init__.py file) for each Blueprint. For example, here is the structure of the Flask User Management example that contains two Blueprints (recipes and users):
(venv) $ tree -L 5
.
├── README.md
├── instance
├── main.py
├── project
│ ├── __init__.py
│ ├── models.py
│ ├── recipes
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates
│ │ └── recipes
│ │ └── index.html
│ ├── templates
│ │ └── base.html
│ └── users
│ ├── __init__.py
│ ├── forms.py
│ ├── routes.py
│ └── templates
│ └── users
│ ├── login.html
│ ├── profile.html
│ └── register.html
├── requirements.txt
└── venv
├── bin
│ ├── activate
| ├── ...
Taking a look at a single Blueprint (users), it encapsulates all of components to handle the user management aspects of the application (defining routes, handling forms, generating templates):
users
├── __init__.py
├── forms.py
├── routes.py
└── templates
└── users
├── login.html
├── profile.html
└── register.html
The subfolders for storing the template files may look strange, but this structure (…/blueprint_name/templates/blueprint_name/) is recommended in the Flask documentation. The template directory for each Blueprint gets added to the search path for template files within your Flask application. With this structure, you can define the templates for each Blueprint within the Blueprint, but still import a base template (in …/project/templates/) that gets shared by all the Blueprints. With this structure, the template file for a Blueprint can be accessed using ‘users/login.html’.
In order to create the Blueprint, an object of the Blueprint class gets instantiated in the __init__.py file of the Blueprint folder:
"""
The users Blueprint handles the user management for this application.
Specifically, 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
This instantiation of the Blueprint specifies the name of the Blueprint (users) and it specifies the location of the template files within the Blueprint. Additionally, the last line imports the routes created in routes.py.
The users_blueprint that was created in __init__.py is then imported in the routes.py file:
#################
#### imports ####
#################
from
.
import
users_blueprint
This import allows the routes that are being created in routes.py to be specified with ‘@users_blueprint’:
################
#### routes ####
################
@users_blueprint
.route(
'/'
)
def
index():
return
render_template(
'index.html'
)
After creating a Blueprint (and registering it), you can check that the routes are being created successfully by checking the mapping of the URLs to specific functions. The best way to see this is to bring up the Python interpreter with the key Flask components loaded using flask shell:
(venv) $ flask shell
>>> print(app.url_map)
Map([<Rule '/register' (OPTIONS, HEAD, GET, POST) -> users.register>,
<Rule '/profile' (OPTIONS, HEAD, GET) -> users.profile>,
<Rule '/logout' (OPTIONS, HEAD, GET) -> users.logout>,
<Rule '/login' (OPTIONS, HEAD, GET, POST) -> users.login>,
<Rule '/' (OPTIONS, HEAD, GET) -> recipes.index>,
<Rule '/static/<filename>' (OPTIONS, HEAD, GET) -> static>])
This shows that the URLs are being mapped correctly to the functions in the Blueprints.
Application Factory
The initialization of a Flask project requires the following steps:
- Creating the Flask application as an instance of the Flask class
- Configuring the Flask application
- Initializing the extensions to be used
- Registering the Blueprints in the project
These steps can be put together in a single function called an Application Factory function (an implementation of the Factory method pattern). In addition to making it clear what steps need to be taken to initialize a Flask application, the Application Factory function allows different Flask applications to be created with different configurations. This flexibility becomes very useful during testing, where the configuration can often be different from development or production.
The Application Factory function is created in the …/project/__init__.py file. To start, import all of the modules (including the Flask extensions) that are needed for the Flask project:
from
flask
import
Flask
from
flask_sqlalchemy
import
SQLAlchemy
from
flask_login
import
LoginManager
from
flask_bcrypt
import
Bcrypt
Next, create the instances of each of the Flask extensions without initializing them:
#######################
#### Configuration ####
#######################
# Create the instances of the Flask extensions (flask-sqlalchemy, flask-login, etc.) in
# the global scope, but without any arguments passed in. These instances are not attached
# to the application at this point.
db
=
SQLAlchemy()
bcrypt
=
Bcrypt()
login
=
LoginManager()
login.login_view
=
"users.login"
Next, the actual Application Factory function (create_app) is defined:
######################################
#### Application Factory Function ####
######################################
def
create_app(config_filename
=
None
):
app
=
Flask(__name__, instance_relative_config
=
True
)
app.config.from_pyfile(config_filename)
initialize_extensions(app)
register_blueprints(app)
return
app
The function to initialize each Flask extension passes in the Flask application to each extension:
def
initialize_extensions(app):
# Since the application instance is now created, pass it to each Flask
# extension instance to bind it to the Flask application instance (app)
db.init_app(app)
bcrypt.init_app(app)
login.init_app(app)
...
Finally, all of the Blueprints are registered with the Flask application:
def
register_blueprints(app):
# Since the application instance is now created, register each Blueprint
# with the Flask application instance (app)
from
project.recipes
import
recipes_blueprint
from
project.users
import
users_blueprint
app.register_blueprint(recipes_blueprint)
app.register_blueprint(users_blueprint)
After creating the Application Factory function, it gets used in the …/main.py file:
from
project
import
create_app
# Call the Application Factory function to construct a Flask application instance
# using the standard configuration defined in /instance/flask.cfg
app
=
create_app(
'flask.cfg'
)
Now the Flask application is ready to run using:
(venv) $ export FLASK_APP=main.py
(venv) $ flask run
* Serving Flask app "main"
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
Overall Structure
The overall structure for this project is shown below:
(venv) $ tree -L 3
.
├── README.md
├── instance
├── main.py
├── project
│ ├── __init__.py
│ ├── models.py
│ ├── recipes
│ │ ├── __init__.py
│ │ ├── routes.py
│ │ └── templates
│ ├── templates
│ │ └── base.html
│ └── users
│ ├── __init__.py
│ ├── forms.py
│ ├── routes.py
│ └── templates
├── requirements.txt
└── venv
├── bin
├── ...
The Blueprints are defined in separate modules in the …/project folder. The Application Factory function is defined in the …/project/__init__.py file. The actual Flask application is then created in …/main.py.
Conclusion
This blog post described how to use Blueprints and an Application Factory function to help structure a Flask project. Blueprints provide a great tool to organize your project into major pieces of functionality. An Application Factory function provides a clean method for creating the Flask application. Put together, these are the two primary ideas that I use to structure a Flask project.
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK