Boilerplate Flask Apps
Reference codebase used in all Flask Apps provided by the AppSeed platform
All Flask Apps generated by AppSeed share the same codebase structure and features:
  • Reference Codebase - Flask Apps Boilerplate
  • SQLite database, Flask-SQLAlchemy ORM
  • Session-Based auth flow (login, register)
  • Deployment scripts: Docker, Gunicorn / Nginx, Heroku
Links
​Support (Email and LIVE on Discord) for registered AppSeed users.
​

Environment

To use the stater, Python3 should be installed properly in the workstation. If you are not sure if Python is properly installed, please open a terminal and type python --version. The full list with dependencies and tools required to build the app:
  • ​Python3 - the programming language used to code the app
  • ​GIT - used to clone the source code from the Github repository
  • Basic development tools (g++ compiler, python development libraries ..etc) used by Python to compile the app dependencies in your environment.
​

Build the app

To built and start the app locally, follow the steps:
Get the source code
  • Download the ZIP from Github Repository
  • Using GIT tool in the terminal to clone the source code
Change the current directory to source code directory
1
$ # Make sure you are running the commands INSIDE source code directory
2
$
3
$ # Create and activate a Virtualenv (Unix based systems)
4
$ virtualenv env
5
$ source env/bin/activate
6
$
7
$ # Create and activate a Virtualenv (Windows based systems)
8
$ # virtualenv env
9
$ # .\env\Scripts\activate
10
$
11
$ # Install requirements
12
$ pip3 install -r requirements.txt
13
$
14
$ # Set the FLASK_APP environment variable
15
$ (Unix/Mac) export FLASK_APP=run.py
16
$ (Windows) set FLASK_APP=run.py
17
$ (Powershell) $env:FLASK_APP = ".\run.py"
18
$
19
$ # Set up the DEBUG environment
20
$ # (Unix/Mac) export FLASK_ENV=development
21
$ # (Windows) set FLASK_ENV=development
22
$ # (Powershell) $env:FLASK_ENV = "development"
23
$
24
$ # Run the application
25
$ # --host=0.0.0.0 - expose the app on all network interfaces (default 127.0.0.1)
26
$ # --port=5000 - specify the app port (default 5000)
27
$ flask run --host=0.0.0.0 --port=5000
28
$
29
$ # Access the app in browser: http://127.0.0.1:5000/
Copied!
At this point, we can visit the app in the browser http://127.0.0.1:5000/. By default, the app will redirect guest users to the login page. To access the private pages:
  • Create a new user using the registration page
  • Authenticate using the login page

​

App Codebase (simplified)

Starter uses a simple codebase (no Blueprints) with a structure presented below:
1
< PROJECT ROOT >
2
|
3
|-- app/ # The actual APP
4
|-- app/__init__.py # App Constructor
5
|
6
|-- requirements.txt # App dependencies
7
|
8
|-- run.py # App Bootstraper (returs the WSGI app)
9
|
10
|-- ***********************************
Copied!

The bootstrap flow

  • run.py imports the WSGI Application from app directory
  • app/__init__.py is called and trigger the following actions:
    • invoke Flask Framework constructor
    • Read the configuration from app/config.py
    • Invoke SQLAlchemy​
    • Invoke LoginManager exposed by Flask-Login​
app/__init__.py (simplified version)
1
# File: /app/__init__.py
2
​
3
from flask import Flask # Import Flask
4
from flask_sqlalchemy import SQLAlchemy # For ORM db access
5
from flask_login import LoginManager # Used for authentication
6
​
7
# Directive 1 - Inject Flask magic
8
app = Flask(__name__)
9
​
10
# Directive 2 - Load the configuraton from `app/config.py`
11
app.config.from_object('app.config.Config')
12
​
13
# Directive 3 - Flask-SqlAlchemy wrapping
14
db = SQLAlchemy (app)
15
​
16
# Directive 4 - Invoke and init the login manager
17
lm = LoginManager( )
18
lm.init_app(app)
19
​
20
# Directive 5 - Setup database (create tables)
21
@app.before_first_request
22
def initialize_database():
23
db.create_all()
24
​
25
# Directive 5 - Start the App
26
from app import views, models
27
​
28
# At this point we have a valid WSGI app
Copied!
The app/__init__.py constructs the app by putting together a short-list of things:
  • Invoke Flask
  • Load the configuration from config.py
  • Invoke the SqlAlchemy ORM to handle the database content
  • Invoke and inject the Login Manager into the app
  • Check if the database tables are created
  • Finally, expose the app by importing views (app routing) and models (app tables)

App Codebase

The codebase structure is presented below:
1
< PROJECT ROOT >
2
|
3
|-- app/
4
| |-- __init__.py # App initializer
5
| |-- config.py # App configuration
6
| |-- forms.py # App Forms
7
| |-- models.py # App Models
8
| |-- util.py # Helpers
9
| |-- views.py # App Routing
10
| |
11
| |-- static/
12
| | |-- <css, JS, images> # CSS files, Javascripts files
13
| |
14
| |-- templates/
15
| | |
16
| | |-- includes/ # Page chunks, components
17
| | | |
18
| | | |-- navigation.html # Top bar
19
| | | |-- sidebar.html # Left sidebar
20
| | | |-- scripts.html # JS scripts common to all pages
21
| | | |-- footer.html # The common footer
22
| | |
23
| | |-- layouts/ # App Layouts (the master pages)
24
| | | |
25
| | | |-- base.html # Used by common pages like index, UI
26
| | | |-- base-fullscreen.html # Used by auth pages (login, register)
27
| | |
28
| | |-- accounts/ # Auth Pages (login, register)
29
| | | |
30
| | | |-- login.html # Use layout `base-fullscreen.html`
31
| | | |-- register.html # Use layout `base-fullscreen.html`
32
| | |
33
| | index.html # The default page
34
| | page-404.html # Error 404 page (page not found)
35
| | page-500.html # Error 500 page (server error)
36
| | *.html # All other pages provided by the UI Kit
37
|
38
|-- requirements.txt
39
|
40
|-- run.py
41
|
42
|-- ************************************************************************
Copied!

App Configuration

The configuration file app/config.py specify a short-list with variables:
This configuration is loaded by app/__init__.py during the app initialization:
1
# File: /app/__init__.py
2
​
3
...
4
​
5
# Directive 2 - Load the configuraton from `app/config.py`
6
app.config.from_object('app.config.Config')
7
​
8
...
9
​
Copied!
The default database is SQLite, configured by the SQLALCHEMY_DATABASE_URI variable:
1
# File: /app/config.py
2
​
3
...
4
​
5
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(basedir, 'db.sqlite3')
6
SQLALCHEMY_TRACK_MODIFICATIONS = False
7
​
8
...
9
​
Copied!
The database and associated tables, defined in app/models.py are automatically created at the first request in the physical file specified in the configuration - default location app/db.sqlite3.
Hint: to visualize the SQLite database content an external tool should be installed: DB Browser for SQLite it might be a good choice.

App Tables

The file app/models.py defines the table(s) used by the application. Being a simple starter, by default the following tabes are defined:
  • Table #1 - User with fields:
    • Id - Primary key, unique
    • user - Store the username
    • email - The email address
    • password - Hashed password

App Forms

The file app/forms.py defines the table(s) used by the application. Being a simple starter, by default the following forms are defined:
  • Form #1 - LoginForm with fields:
    • username
    • password
  • Form #2 - RegisterForm with fields:
    • name - The friendly name
    • username - used to authenticate
    • password - used to authenticate
    • email

App Routing

The file app/views.py defines the application routing. Here is the list with defined paths and associated handlers

Route /login.html

The route handles the app authentication using a simple flow:
  • Loads LoginForm defined in app/forms.py
  • GET request
    • loads the page app/tempates/accounts/login.html
  • POST request
    • Validate the input data: username, password
    • Locate the user in the database
    • Verify the password against the database version
    • For success, authenticate the user
    • For errors, reload the login page and inform the user

Route /register.html

The route handles the app authentication using a simple flow:
  • Loads RegisterForm defined in app/forms.py
  • GET request
    • loads the page app/tempates/accounts/register.html
  • POST request
    • Validate the input data: username, password, email
    • Check if username or email is already registered
    • Hash the password provided by the user
    • Save the user in the database
    • Reload the registration page and inform the user

Route /logout.html

The route delete the user session and redirect the user to the login.html

Default Route /

The route will serve all pages defined in the app/templates for the authenticated users using a simple flow:
  • Check user is authenticated
  • Redirect to /login.html guests users
  • Load the requested page from app/templates folder
  • Return Error 404 and associated page if requested page cannot be located
  • Return Error 500 if a critical error occurred during the page load

Pages & Assets

Pages served by the starter are organized using a simple folder structure:
1
< PROJECT ROOT >
2
|
3
|-- app/
4
| |
5
| |-- static/assets/
6
| | |-- <css, JS, images> # CSS files, Javascripts files
7
| |
8
| |-- templates/
9
| | |
10
| | |-- includes/ # Page chunks, components
11
| | | |
12
| | | |-- navigation.html # Top bar
13
| | | |-- sidebar.html # Left sidebar
14
| | | |-- scripts.html # JS scripts common to all pages
15
| | | |-- footer.html # The common footer
16
| | |
17
| | |-- layouts/ # App Layouts (the master pages)
18
| | | |
19
| | | |-- base.html # Used by common pages like index, UI
20
| | | |-- base-fullscreen.html # Used by auth pages (login, register)
21
| | |
22
| | |-- accounts/ # Auth Pages (login, register)
23
| | | |
24
| | | |-- login.html # Use layout `base-fullscreen.html`
25
| | | |-- register.html # Use layout `base-fullscreen.html`
26
| | |
27
| | index.html # The default page
28
| | page-404.html # Error 404 page (page not found)
29
| | page-500.html # Error 500 page (server error)
30
| | *.html # All other pages provided by the UI Kit
31
|
32
|
33
|-- ************************************************************************
Copied!

Static Assets

The folder contains the assets provided by the UI Kit integrated into the app. AppSeed conversion scripts will modify the original UI kit path to match the structure:
  • static/assets - the root directory for all files (JS, images)
  • static/assets/css - CSS files that style the app
  • static/assets/img - Images and Icons
  • static/assets/js - javascript files provided by the UI Kit
  • static/assets/scss - SCSS files, if provided by the UI Kit vendor

Templates Folder

All pages served by the application are located inside this folder.
  • templates/layouts - the directory with app layouts
  • templates/includes - the directory with HTML chunks and components
  • templates/accounts - store the authentication pages (login, registration)
  • templates/ - all pages defined/served by the app are saved at the root of the templates folder

Common pages

This section lists the common pages defined in all Flask applications prototyped on top of this generic starter.
  • login.html, rendered with layouts/base-fullscreen.html
  • register.html, rendered with layouts/base-fullscreen.html
  • index.html, rendered with layouts/base.html
  • page-404.html, rendered with layouts/base.html
  • page-403.html, rendered with layouts/base.html

Data Structures

The Flask starter exposes a short-list with data structures used globally across the app:

current_user object

Constructed by Flask-Login can be used to detect if the current request is executed by an authenticated user or not. The object has global visibility and can be used in all app controllers and handlers but also in views.
How it works
app/views.py define a callback function required by Flask-Login library:
1
# File: app/views.py
2
​
3
# *****************************************
4
# `lm` is constructed in `app/__init__.py`
5
#
6
# lm = LoginManager( ) # flask-loginmanager
7
# lm.init_app(app) # init the login manager
8
#
9
# *****************************************
10
#
11
# provide login manager with load_user callback
12
@lm.user_loader
13
def load_user(user_id):
14
return User.query.get(int(user_id))
Copied!
Usage in contoler
1
# File: app/views.py
2
​
3
def index(path):
4
​
5
# Redirect guests users to login page
6
if not current_user.is_authenticated:
7
return redirect(url_for('login'))
Copied!
Usage in view
1
<div class="collapse navbar-collapse" id="navigation">
2
<ul class="navbar-nav ml-auto">
3
​
4
<!-- The Usage of <current_user> object -->
5
{% if current_user.is_authenticated %}
6
​
7
<!-- Html chunk rendered for authenticated users-->
8
​
9
<li class="nav-item">
10
<a href="/" class="nav-link text-primary">
11
<i class="tim-icons icon-minimal-left"></i> Back to Dashboard
12
</a>
13
</li>
14
​
15
{% else %}
16
​
17
<!-- Html chunk rendered for guests users-->
18
​
19
<li class="nav-item ">
20
<a href="{{ url_for('register') }}" class="nav-link">
21
<i class="tim-icons icon-laptop"></i> Register
22
</a>
23
</li>
24
<li class="nav-item ">
25
<a href="{{ url_for('login') }}" class="nav-link">
26
<i class="tim-icons icon-single-02"></i> Login
27
</a>
28
</li>
29
​
30
{% endif %}
31
​
32
</ul>
33
</div>
Copied!
​
Last modified 6mo ago