Hello Coders,
This article presents a shortlist with useful hints and features that might help developers code faster a Flask project. For newcomers, Flask is a lightweight WSGI web application framework designed to get started quickly and easily, with the ability to scale up to complex applications.
Thanks for reading! - Content provided by App Generator.
- ✨ Section 1# - How to
code a simple App
in Flask - ✨ Section 2# -
How to structure
your project - ✨ Section 3# - How to
enable DEBUG
- ✨ Section 4# - How to
set up SQLAlchemy
- ✨ Section 5# - How to
use the Flask CLI
- ✨ Section 6# - How to
migrate a Database
- ✨ Section 7# - How to define and
use a form
- ✨ Section 8# - How to
implement authentication
- ✨ Section 9# - How to read
POST data
- ✨ Section 10# - How to
redirect in Flask
- ✨ Section 11# -
Logging
in Flask - ✨ Section 12# - How to
return JSON
in Flask - ✨ Section 13# - How to
enable CORS
- ✨ Section 14# - Access the
app
object anywhere in our project - ✨ Section 15# - A curated index with Free Dashboards
- 🔥 Flask Soft UI - Bootstrap 5 Dashboard
- 🔥 Flask Pixel UI Kit - Bootstrap5 UI Kit
- 🔥 Datta Able Flask- colorful BS4 Design
- 🔥 Flask Bootstrap 5 Volt - Bootstrap 5 design
- 🔥 Flask Dashboard Black - Dark-themed dashboard
Ok, let's get back to the real content - the first one is pretty basic and explains how to code a minimal Flask app in less than 1 minute (you need to type fast and have Python3 installed).
✨ 1# - Flask, a minimal app
Open a terminal and install Flask using PIP:
$ pip install Flask
Use your preferred editor to create a file called hello.py
:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return f'Hello from Flask!'
Once the file is saved, let's start the app:
$ env FLASK_APP=hello.py flask run
* Serving Flask app "hello"
* Running on http://127.0.0.1:5000/
By visiting the app in the browser we should see "Hello from Flask" message.
✨ 2# - How to structure your project
Being such a lightweight framework, Flask comes with great flexibility regarding the codebase structure of a project. The one suggested in this article has been used in many Flask starters generated by the AppSeed platform but we are pretty sure there are many other good configurations published on Github or private blogs.
< PROJECT ROOT >
|
|-- app/__init__.py
|-- app/
| |-- static/
| | |-- <css, JS, images> # CSS files, Javascripts files
| |
| |-- templates/
| | |
| | |-- includes/ # Page chunks, components
| | | |
| | | |-- navigation.html # Top bar
| | | |-- sidebar.html # Left sidebar
| | | |-- scripts.html # JS scripts common to all pages
| | | |-- footer.html # The common footer
| | |
| | |-- layouts/ # App Layouts (the master pages)
| | | |
| | | |-- base.html # Used by common pages like index, UI
| | | |-- base-fullscreen.html # Used by auth pages (login, register)
| | |
| | |-- accounts/ # Auth Pages (login, register)
| | | |
| | | |-- login.html # Use layout `base-fullscreen.html`
| | | |-- register.html # Use layout `base-fullscreen.html`
| | |
| | index.html # The default page
| | page-404.html # Error 404 page (page not found)
| | page-500.html # Error 500 page (server error)
| | *.html # All other pages provided by the UI Kit
|
|-- requirements.txt
|
|-- run.py
|
|-- ************************************************************************
The relevant files:
-
run.py
- the entry point used to start the application -
requirements.txt
- a file that specifies all dependencies (for now is just Flask) -
app
- the application folder where we will add our code -
app/__init__.py
- This file is required to let us use the app as a Python Package -
app/static
- this folder will contain design assets: JS, CSS, and images. -
templates
- the directory with pages, layouts, and components used by Flask to generate some nice pages for us
✨ 3# - How to enable DEBUG
Sometimes during our development we need to investigate errors in deep by checking the variables values, freeze the application execution and inspect the context or visualize a filtered products list in the user shopping cart. We can achieve this in two ways:
- using logs and inject print() statements all over the place
- using a Debugger and gain full control over the app without writing non-functional code in all controllers and helpers.
Flask comes with a Built-in Debugger that allows us to inspect in deep application runtime execution. Flask automatically detects and enable the debugger by scanning the application environment:
$ export FLASK_ENV=development
$ flask run
When running from Python code, the app object accepts the debug variable as an argument:
app.run(debug=True)
At this point, app should run in DEBUG more. Another useful option is to use the debugger toolbar plugin.
Adding an external Debugger Toolbar
This plugin provides useful runtime information like HTTP Headers, configuration, rendered templates, and SqlAlchemy queries executed during requests.
To enable these features is pretty easy. First, we need to install the plugin (via PIP).
$ pip install flask-debugtoolbar
The next step is to use the extension over our Flask app:
from flask import Flask
from flask_debugtoolbar import DebugToolbarExtension
app = Flask(__name__)
# the toolbar is only enabled in debug mode:
app.debug = True
# set a 'SECRET_KEY' to enable the Flask session cookies
app.config['SECRET_KEY'] = '<replace with a secret key>'
toolbar = DebugToolbarExtension(app) # <--- NEW
If your product uses app-factory pattern to construct the Flask application, please use this code snippet:
...
# Initialize the Debug Toolbar
toolbar = DebugToolbarExtension() # <--- NEW
# Make sure the app has DEBUG enable
app = create_app()
# Inject the toolbar object in the Flask app object
toolbar.init_app(app) # <--- NEW
...
For more information related to Debugging in Flask, please access
- Debugging Application Errors - Flask documentation
- Debugger Toolbar - aka Flask-DebugToolbar module
✨ 4# - How to set up Flask-SQLAlchemy
Flask-SQLAlchemy is a wrapper over the popular SQLAlchemy Python toolkit that empowers developers to manage a database using an object-oriented approach.
The setup required by Flask-SqlAlchemy is minimal:
$ pip3 install flask_sqlalchemy
Once the package is installed, we can use it in the source code:
from flask import Flask
# Import SQLAlchemy
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# Define the database
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////tmp/test.db'
# Inject SQLAlchemy magic
db = SQLAlchemy(app)
# Sample model handled by SqlAlchemy
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
def __repr__(self):
return '<User %r>' % self.username
To effectively create User table in the database, we need to use the Flask CLI (see the next section)
More SQLAlchemy resources
- SQLAlchemy - toolkit page
- Flask-SQLAlchemy - Flask wrapper documentation
✨ 5# - How to use the Flask CLI
To use the Flask CLI, FLASK_APP
environment variable should point to the application bootstrap script. Once we have this variable present in the working environment, we can launch the Flask console and interact with our application in a different way:
$ export FLASK_APP=app # adjust to match your entry point
$ flask shell
Using the CLI we can create the table defined in the previous section:
$ flask shell
>>> from app import db #
>>> db.create_all() # All tables are created
Using the CLI we can select and update users (or any other defined tables) as well:
$ flask shell
>>> from app import User
>>> User.query.all()
[<User u'admin'>, <User u'guest'>]
For more resources, please access:
- Flask CLI - module documentation
- Define custom commands - a comprehensive section on this topic
✨ 6# - How to migrate a Database
A migration means our database has changed:
- New table added
- The existing table is updated with a new column
- The type of an existing column has changed. For instance, we have a column that stores 100 characters and we need to extend it to 500.
To safely update the database, we need to "migrate" to the new structure. The Flask plugin that saves us from doing the dirty work is Flask Migrate.
$ pip install Flask-Migrate
To effectively work, Flask-Migrate must be injected in the Flask object:
...
app = Flask(__name__)
...
migrate = Migrate(app, db) # <- The magic line
If we execute the migration for the first time, we should run:
$ # This will create the migrations folder
$ flask db init
Let's update the User model with a new field: role
# Sample model handled by SqlAlchemy
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
# The new field
role = db.Column(db.Integer, primary_key=False)
To update the database, two steps are required: generate the SQL according to our change and apply it on the database.
Generate the SQL
$ flask db migrate
Update the Database - using the SQL generated in the previous step
$ flask db upgrade
At this point, we can inspect the table to visualize the presence of the role column and use it in our code.
Resources
- Flask-Migrate - the official module documentation
- Flask – Setting up Postgres, SQLAlchemy, and Alembic - a nice tutorial on this hot topic
✨ 7# - How to define and use a form
Flask assists us a lot regarding forms via a dedicated library: flask_wtf/FlaskForm. We can easily define, secure, and validate forms using this package.
Here is the definition of a Login form:
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField
class LoginForm(FlaskForm):
username = StringField (u'Username' , validators=[DataRequired()])
password = PasswordField(u'Password' , validators=[DataRequired()])
As mentioned, FlaskForm comes with re-defined types and validators for the password, mandatory fields check, email, and much more.
The view (aka the page) that use it:
<form role="form" method="post" action="">
{{ form.username(placeholder="Username") }}
{{ form.password(placeholder="Password",type="password") }}
</form>
For newcomers, a simplified CSRF mechanism is presented below:
- Server generates the CRSF Token
- Form is built and sent to the client browser along with the token
- The user fills and submits the form
- The server receives a new POST request and check the CSRF token authenticity
- If the token is not validated request is rejected with a 403 (not authorized) status
More resources
- Creating Forms in Flask
- CSRF Protection in Flask - how to use it
✨ 8# - How to authenticate in Flask
Flask-Login provides user session management for Flask. It handles the common tasks of logging in, logging out, and remembering users’ sessions.
Let's highlight the code to integrate Flask-Login in a real application.
Update your User model to inherit the UserMixin class. This is necessary because Flask expects a minimum set of handlers to be implemented by the user model: is_authenticated, is_active, get_id. To skip over this work, UserMixin class saves the day for us.
from app import db
from flask_login import UserMixin
# User model uses UserMixin as parent class
class User(UserMixin, db.Model):
id = db.Column(db.Integer, primary_key=True)
user = db.Column(db.String(64), unique = True)
email = db.Column(db.String(120), unique = True)
password = db.Column(db.String(500))
The next step is to define user_loader a method used by Login-Manager to identify the current authenticated user information: id, email and all other fields provided by the User class.
...
# provide login manager with load_user callback
@lm.user_loader
def load_user(user_id):
return User.query.get(int(user_id))
...
Once we have the User table updated in the database, we can successfully login.
The login view (aka login page):
...
<form method="post" action="" class="mt-4">
{{ form.hidden_tag() }}
{{ form.username(class="form-control") }}
{{ form.password(class="form-control", type="password") }}
<button type="submit" name="login">Sign in</button>
</form>
Once the user fills username and the password, all information is sent to the server via a POST request.
Login - The controller code
# Authenticate user
@app.route('/login.html', methods=['GET', 'POST'])
def login():
# Declare the login form
form = LoginForm(request.form)
# The information returned to the user
msg = "Your cool!"
# Apply all validations defined in the form
if form.validate_on_submit():
# recover form information
username = request.form.get('username', '', type=str)
password = request.form.get('password', '', type=str)
# recover the user from database using username (unique information)
user = User.query.filter_by(user=username).first()
# If the user is found, validate the password
if user:
# BC = BCrypt library
if bc.check_password_hash(user.password, password):
# The user is now authenticated
login_user(user)
else:
msg = "Wrong password. Please try again."
else:
msg = "Unknown user"
return render_template( 'accounts/login.html', form=form, msg=msg )
The controller flow explained:
- Local variable form is initialized using the request form (sent by the user)
- If the form is valid (user and password are present) the code extracts the values
- Select the user from the database using the name
- Check the password by comparing the database value with the one provided by the user and hashed by the BCrypt library.
- If all is good, the user session is created via "login_user()" handler
- Error cases are flagged with a message to inform the user what was wrong.
Flask authentication resources:
- Flask-Login - the concerned module
- LoginManager class definition
✨ 9# - How to read POST data
For newcomers, POST and GET are different methods used to submit information to a server. During a GET request, the variables are appended to the page URL:
GET/login.html?user=Biden&pass=MAGA2020
POST requests use the request body to bundle the information submitted by the user.
In both cases, we can easily read POST and GET parameters with Flask via the request object. Here is a list of request objects that we can refer to extract the information:
- request.args: the key/value pairs in the URL query string
- request.form: the key/value pairs in the body, from a HTML post form
- request.json: parsed JSON data
A real sample - used to handle registration flow
@app.route('/register.html', methods=['GET', 'POST'])
def register():
# declare the Registration Form
form = RegisterForm(request.form)
# request is GET - just display the form
if request.method == 'GET':
return render_template( 'accounts/register.html', form=form, msg=msg )
# Here we have a POST request
if form.validate_on_submit():
# READ information from a POST request
username = request.form.get('username', '', type=str)
password = request.form.get('password', '', type=str)
email = request.form.get('email' , '', type=str)
As mentioned above, the composite request.form provides the form fields in key/value pairs bundled in the request body.
More information on this topic:
- Flask request Args - object information
- Get the data received in a Flask request - Related StackOverflow topic
✨ 10# - How to redirect in Flask
This is a simple one. Flask exposes a "redirect" handler to keep us lazy:
import os
from flask import Flask,redirect
app = Flask(__name__)
@app.route('/')
def not_me():
# redirect to another page
return redirect("/register")
# redirect to external page
return redirect("https://google.com")
# redirect with HTTP code
return redirect("https://google.com", code=301)
Resources:
- Flask redirect - handler docs
- Flask redirect Example - tutorial provided by Full-Stack Python
✨ 11# - Logging in Flask
Flask uses the native Python logging system (no configuration required). To log a message during a request, we need to call the logger interface and set the message we want to be visible in logs:
from flask import Flask
import logging
app = Flask(__name__)
logging.basicConfig(level=logging.DEBUG)
@app.route('/')
def hello():
app.logger.info('Logging is up!')
return 'Hello World!'
if __name__ == '__main__':
app.run()
By running the app, we should see the logging message in the console:
* Serving Flask app "app.py"
* Environment: development
INFO:werkzeug: * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
INFO:flask.app:Logging is up
INFO:werkzeug:127.0.0.1 - - [01/Jun/2019 17:03:09] "GET / HTTP/1.1" 200 -
Logs might be useful when we want to trace runtime errors in production or save other relevant events in the logs for the application owner.
The above sample will push the log to the console but we can easily push messages to a file:
from flask import Flask
import logging
app = Flask(__name__)
logging.basicConfig(filename='app.log', level=logging.DEBUG)
@app.route('/')
def hello():
app.logger.info('Logging is up!')
return 'Hello World!'
if __name__ == '__main__':
app.run()
After a first request, a new file named "app.log" should be created with our log message as content.
Flask logging resources
- Flask Logging - the official module documentation
- Flask Logging - Get starter quickly - a nice tutorial.
✨ 12# - How to return JSON
Flask comes with native support for JSON management via jsonify interface. Let's take a look at this self-descriptive sample:
from flask import jsonify
@app.route('/_get_current_user')
def get_json():
return jsonify(
message="Hello",
from="from JSON"
)
The output returned in the browser should be as below:
{
"message": "Hello",
"from": "from JSON"
}
Something useful: let's return a registered user using JSON format:
from flask import jsonify
@app.route('/user_json')
def get_json():
user = User.query.filter_by(username='testme').first()
# Using the user object (without __dict__) will generate a runtime error
# TypeError: 'user' is not JSON serializable
return jsonify( user.__dict__ )
The response should contain all fields defined in the User table:
{
"id": "1",
"username": "testme",
"email":"test@google.com"
}
More resources:
- Flask jsonify - class documentation
- Serializing class instance to JSON - related StackOverflow topic
✨ 13# - How to enable CORS in Flask
This feature is useful when our Flask backend is consumed by decoupled entities like a mobile UI interface, external systems that push or request the information provided by the Flask backend.
As usual, Flask has a module for this flask-cors.
$ Install the module via PIP
$ pip install -U flask-cors
Let's take a look at the sample provided in the official docs:
from flask import Flask
from flask_cors import CORS
app = Flask(__name__)
CORS(app)
@app.route("/")
def helloWorld():
return "Hello, cross-origin-world!"
We can also isolate CORS for specific paths like /api/*:
app = Flask(__name__)
cors = CORS(app, resources={r"/api/*": {"origins": "*"}})
@app.route("/api/v1/users")
def list_users():
return "user example"
CORS Resources
- Flask-CORS - official documentation
- What is CORS - a tutorial provided by Codecademy
✨ 14# - Access the app
object
When we are coding a Flask project using more than one file and the complexity rises, we might need to access the Flask app
constructed by the project during the initialization. We can achieve this pretty easily by accessing current_app
object provided by Flask itself.
from flask import Flask
from flask import current_app
from flask_cors import CORS
# This is the constructed bject
app = Flask(__name__)
current_app # here is the reference to "app" object
# we can do this in any file
✨ 15# - Open-source Samples
All projects mentioned below can be downloaded without a registration lock and used for unlimited hobby & commercial projects.
🔥 Flask Soft UI
Free dashboard crafted in Flask Framework, designed for those who like bold elements and beautiful websites, Soft UI Dashboard is ready to help you create stunning websites and webapps.
Flask Soft UI - product page (contains DEMO & sources)
🔥 Flask Pixel UI Kit
Open-Source Flask starter coded with basic modules, database, ORM and deployment scripts on top of Pixel Lite UI Kit, a fully responsive and modern Bootstrap 5 UI Kit that will help you build creative and professional websites. The Flask codebase comes with basic modules, database, ORM and deployment scripts.
Flask Pixel UI Kit - product page (contains DEMO & sources)
🔥 Datta Able Flask
Datta Able Bootstrap Lite is the most stylized Bootstrap 4 Lite Admin Template, around all other Lite/Free admin templates in the market. It comes with high feature-rich pages and components with fully developer-centric code. Before developing Datta Able our key points were performance and design.
Datta Able Flask - product page (contains DEMO & sources)
🔥 Flask Bootstrap 5 Volt
Volt Dashboard is a free and open source Bootstrap 5) dashboard template featuring over 100 components, 11 example pages and 3 plugins with Vanilla JS. There are more than 100 free Bootstrap 5 components included some of them being buttons, alerts, modals, datepickers and so on.
Flask Bootstrap 5 Volt - product page (contains DEMO & sources)
🔥 Flask Dashboard Black
Flask Black Dashboard is an open-source Flask Dashboard generated by AppSeed on top of a modern dark-themed UI. Black Dashboard is a beautiful Bootstrap 4 Admin Dashboard with a huge number of components built to fit together and look amazing.
Flask Dashboard Black - product page (contains DEMO & sources)
Thanks for reading! For more resources, feel free to access:
- 👉 More Flask Dashboards crafted in Django, Flask, and
React
- 👉 More Flask Apps - free & PAID
Top comments (15)
Thanks for this great post! It is very useful for me. I'm starting learning python + flask + PostgreSQL
🚀🚀
Thank you for providing an overall summary of basic functionality used in web app implemented by flask. It will be a lot helpful if you could make an indetail article for signup and login functionality
Noted! Ty for reading!
Flask is awesome.
Especially for beginners.
Thank you! Really nice content.
Yw!
Wow. Really helpful. Appreciate your efforts.
This is awesome man! Thank you!
Yw!
Wow, what an article. I am on learning Flask for everything in web development. Thank you for sharing.
Glad you like it! More will come.
Flask is such a great piece of software.
Awesome..
Yw!