I enjoy working with Flask and made lots of websites with this framework. I can build anything I want, and I'm grateful for the freedom it gives me as a developer. Flask-Backbone is my take to create an initial structure and a set of rules, so most of my flask projects are easy to support. I already use it when developing new projects.
The other reason why I started Flask-Backbone is that I understand how it can be difficult sometimes for new developers to dive into new technology. Flask for a newbie is a kind of double sword. It's easy to start, but when you need to grow bigger you end up with a bunch of smelly code.
In Flask-Backbone I used patterns from the official documentation, so you won't have any troubles making your customizations and growing from this point.
You can think of Flask-Backbone as an IKEA manual. It's a boilerplate. You can learn how things work in Flask and you can also create big projects without any limitations. I use it every day at my work.
Note: Although Flask is an awesome tool, for API services I would suggest Falcon, FastApi or other API-centric frameworks. Remember that being a software engineer means choosing the right tools. Don't worry, if you decided to use Flask to build API-service you'll be fine as well.
Flask-Backbone is boilerplate, but I've added a few tools for interactivity. I also decided not to publish most of my utils to keep things simple. I will probably publish them later as separate libs.
I18N. I removed support for localization. It's a more complex topic and will be covered in a separate article.
While this article explains some terminology about Flask, it can't replace Flask documentation. If you're a newbie you'll need to read about some Flask ideas along the way, so keep Flask documentation around.
Predefined basic structure, so you'll end up with a clean architecture.
Database support via SQLAlchemy 2+. However, you can skip database setup and use Flask-Backbone without the database. Personally, I do not use Flask-SQLAlchemy, but you can.
Development/Production/You own configs with instance_relative_config.
Cache support via flask_caching. Setup easily with configuration.
Flask-Debug
Sentry support. Just add your DSN, and you're good to go.
Jinja filters and custom variables.
Designed to be blueprint-first. Keep your structure clean and steady with blueprints. Everything is a blueprint. Your future self will thank you.
Interactive commands to create your next blueprint. Define your blueprint skeletons to speed up your development. To create your next blueprint simply run flask app create-blueprint. It's up to you and you can completely ignore or remove this part and everything will work perfectly fine.
app/blueprints. This is where your blueprints live. More about this in the blueprints section of this article.
app/commands. Application wide commands. For example, here I placed scripts to manipulate blueprints.
app/enums. Place here your application wide python enums. It won't be covered in this article, and it's totally up to you how to use
enums.
app/ext. Application extensions. You'll find here SQLAlchemy, Sentry, Flask-Caching.
You can think of it as a some sort of abstraction. Configure here external libraries and invoke them from this place anywhere in your app.
app/errors. Register here your application error-handlers. For example 404. Inside you'll find a function register_error_handlers.
app/jinja. Jinja configuration.
app/jinja/__init__.py. Jinja mapper definition.
app/jinja/context_processor.py. Jinja context processor. Set here any keys that you want to pass to templates.
app/models. Application-wide models. Other models must be stored in the blueprints.
app/static. Shared static files.
app/templates. Shared templates. Usually I place here main layout and error pages.
app/app.py. This is main flask file. Your application central point.
config. Place here your configurations. Do not store here any sensitive information, since this files will be in git. By default, Flask-Backbone ships with default.py, development.py, and production.py.
instance/config.py. This is where you store your sensitive configurations, like API-keys, database URI, etc. This file must be added in .gitignore.
configure.py. Just a small utility for your initial setup. This script will ask your some questions and will create config files.
requirements.txt. Your app requirements.
webservice.ini. uWSGI config for your deploy.
wsgi.py. This is your entry point to deploy application.
Next. As a rule of thumb, make sure that you use a virtual environment. For example python3 -m venv pythonenv. This will create an environment in the folder pythonenv. I prefer to name my python environment as a pythonenv, because it's more descriptive.
In this post, I'll talk about filters. Jinja2 has a list of built-in filters, and Flask leverages them.
Configuration Basics
Configuration is based on python files. I used to have configuration based on ini files aka "configuring from data files", but it's not sustainable long-term and introduces a lot of limitations. Using python configuration files gives you more freedom, and I feel like it's more pythonic.
In the config folder, you will find three files: default.py, development.py, and production.py. These files are made to be in the repository. They contain general configuration and must not contain any sensitive information about your project. You can create as many configuration files as you want. Environment variable APP_CONFIG value is the name of the config file. For example, if you set APP_CONFIG=test, then config/test.py will be used. By default, it's a development.
Where to store your secrets?instance/config.py is made specifically for this. Don't forget that this file must not be shared in git. This is where you put SECRET_KEY and SQLALCHEMY_DATABASE_URI.
default.py. Your standard config. Any values from this file can be redefined in the development.py or your custom config file.
How does configuration implemented?
This is code from app.py. Go ahead and customize for your needs.
def init_configuration(app: Flask) -> None:
# Load the default configuration
app.config.from_object('config.default')
# load configuration from .env
app.config.from_prefixed_env()
# Variables defined here will override those in the default configuration
app.config.from_object(f"config.{os.environ.get('APP_CONFIG')}")
# Load the configuration from the instance folder
app.config.from_pyfile('config.py')
from flask import current_app
@blueprint.route("/", methods=["get"])
def index_route():
print(current_app.config.get("IMAGES_CDN_URL"))
Default URL Redirect
By default, the application is set to redirect from example.com/url/ to example.com/url. If you want to change or remove this behavior, then go to app.py and change this code.
@app.before_request
def app_before_request():
request_path = request.path
# redirect: example.com/url/ -> example.com/url
if request_path != '/' and request_path.endswith('/'):
return redirect(request_path[:-1], 301)
Blueprints
A Blueprint is a way to organize a group of related views and other code. Rather than registering views and other code directly with an application, they are registered with a blueprint. Then the blueprint is registered with the application when it is available in the factory function.
from Flask documentation
Let's take a look at our app/blueprints folder structure. Home for your blueprints.
__boilerplate__. I will cover this part later, but this is the place where blueprint templates are stored. Command flask app create-blueprint use this folder as a boilerplate. You can also create your own set of blueprints and put them here.
__init__.py. Blueprints central point. All blueprints are connected here to your app instance. Check the source code for the explanation. You'll find the function register_blueprints(app) which is used to automatically connect your blueprints. You can customize register_blueprints to do this manually.
utils.py. Blueprints technical utilities.
index_page. Blueprint folder. In this case, it's a blueprint for the index page.
index_page/routes.py. Blueprint routes like @blueprint.route("/", methods=["get"])
index_page/views. Define your route functions from routes.py here. If you have simple routes you can place them in the routes.py and skip views.
index_page/commands. Blueprint-related commands. In most cases, you won't need them. This part will be explained later in this article.
index_page/utils. Blueprint-related utils. Any small functions that is used across your blueprint.
Create Blueprint
To create your next blueprint simply use flask custom command:
flask app create-blueprint
The script will ask you some questions about your new boilerplate and as a result, you'll have a new blueprint structure. From this point you'll just need to open files and edit according to your needs.
What is a view style?
View style is based on Flask patterns:
Standard (url rule decorator). This is referred to Basic Reusable View. In your routes.py you'll have standard blueprint route decorator.
flask.views.View. This option will create two files: routes.py and views/{blueprint_name}.py. If you're familiar with Flask you understand that this is related to
View Classpattern. Your route view will be placed to the views folder.
flask.views.MethodView. Similar to flask.views.View, but MethodView.
Don't want to use script? No problem. Do it on your own, but there are a few rules that you must follow:
Your blueprint must have a routes.py file.
Inside of your routes.py, you must expose the blueprint variable.
That's it! You're good to go. However, for consistency I suggest you keep the blueprint structure as defined in app/blueprints/__boilerplate__/skeletons/standard.
⚠️ By default, all blueprints are initialized automatically, based on the app/blueprints folder structure. It's easy to change. Check app/blueprints/__init__.py for the detailed explanation.
Working With The Database
Flask-Backbone uses SQLAlchemy 2 as ORM. To use a database, don't forget to set your SQLALCHEMY_DATABASE_URI in instance/config.py. If you remember, you've been asked about this in the first step.
Here is a short snippet on how to copy text to the clipboard with Javascript. Your visitors will thank you. Most likely not, but here we are.
Commands
Commands are implemented using Click, and it's a clear way to define both your application commands and blueprint commands. Read the official
Flask documentation.
Run flask in your shell to view available commands.
Application
Place your application commands in the app/commands. Go there and check available commands source code. It will pretty much explain everything. One thing you must understand is that application commands must be related to application logic. If you want to do something related to the blueprint then do it in your blueprint folder.
flask app create-blueprint
flask app list-blueprints
Blueprint
Let's create our first blueprint command. As a developer, I want to be able to run flask about me command.
1. Go to your about blueprint, open or create commands/__init__.py and add next code:
import click
from flask import current_app
from flask.cli import with_appcontext
@click.command('me')
@click.option('--name', prompt='Enter your name')
@with_appcontext
def command_about_me(name):
click.echo(f"Your name: {name}")
def init_blueprint_cli(blueprint):
blueprint.cli.add_command(command_about_me)
We created our first command with Flask and click. Don't forget to use @with_appcontext decorator for application context.
This way you can use, for example current_app.config.get("MY_CONFIG").
2. Register commands in your blueprint. Open routes.py and add new code.
from app.blueprints.about.commands import init_blueprint_cli
# ... your blueprint routes ...
init_blueprint_cli(blueprint)
Finally, test your command.
flask about me
Enter your name: Dmitry
Your name: Dmitry
Extensions
Flask-Caching
To enable Flask-Caching, change CACHE_TYPE in your instance/config.py. By default it's "NullCache" which means that caching is disabled.
Explore Flask-Caching documentation for possible options and set them in your instance/config.py
Some aspect isn't covered here, but I feel like right now it would make this article more chaotic. If you're an experienced developer you probably won't need much reading, and you'll understand everything just by reading the code. Most of the code is based on the official Flask patterns. Don't be shy and contact me if your have anything to say.
Sometimes I need to upload large CSV files to PostgreSQL. CSV file might have hundreds of columns, that's why i want a tool that can do some magic for me.
Sitemaps are important. Especially for big websites. It is always a good idea to develop your website with SEO in mind. Unfortunately, most developers ignore this part.