A cheat-sheet for creating web apps with the Flask framework using the Python language.
- Creating a Simple App
- Structuring an Application with Blueprints
- Creating Object-Based Configuration
- Using the Jinja2 Template Engine
- Creating Models with SQLAlchemy
- Using Database Migrations
- Creating a Login Manager
- Connecting to a MySQL database
- Create a module called
app.py:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return 'Hello, World!'
if __name__ == '__main__':
app.run()- Example project tree for a project called
project:
run.py
project/
__init__.py
config.py
forms.py
models.py
admin/
__init__.py
routes.py
main/
__init__.py
routes.py
templates/
index.html
static/
css/
style.css
- In
run.py:
from project import app
if __name__=='__main__':
app.run()- In
project/__init__.py:
from flask import Flask
from project.main.routes import main
from project.admin.routes import admin
app = Flask(__name__)
app.register_blueprint(main, url_prefix='/')
app.register_blueprint(admin, url_prefix='/admin')- In
project/main/routes.py:
from flask import Blueprint
main = Blueprint('main', __name__)
@main.route('/')
def index():
return "Hello, World! This is the main page."- In
project/admin/routes.py:
from flask import Blueprint
admin = Blueprint('admin', __name__)
@main.route('/')
def index():
return "Hello, World! This is the admin page."- Create
project/config.py:
class BaseConfig(object):
SECRET_KEY = os.environ.get('SECRET_KEY') or 'abcdef123456'
DEBUG = False
TESTING = False
class DevelopmentConfig(BaseConfig):
DEBUG = True
TESTING = True
class TestingConfig
DEBUG = False
TESTING = True- And then in
__init__.pyinclude:
from flask import Flask
from threechan import config
app = Flask(__name__)
app.config.from_object(config.DevelopmentConfig)- Rendering a template from
main/routes.py:
from flask import Blueprint, render_template
@main.route('/')
def home():
posts = [
{
"body": "Hello, this is a post",
"timestamp": "This is a date and time",
}
]
return render_template("home.html", posts=posts)- Using Jinja2 inside
templates/home.html:
{% for posts in posts %}
<div>
{{ post.body }} <br>
{{ post.timestamp }}
</div>
{% endfor %}- Using filters:
{{ body|upper }}- Creating custom filters:
@main.template_filter('trim_upper')
def string_trim_upper(value):
return value.strip().upper()- Using
extends:
in index.html
{% extends 'base.html' %}
{% block content %}
<p>
Hello, world!
</p>
{% endblock %}in base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width initial-scale=1">
</head>
<body>
{% blockcontent %}{% endblock %}
</body>
</html>- Using
includes:
{% includes '_post.html' %}- Adding a stylesheet from
templates/base.html:
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">- In
project/models.py:
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
body = db.Column(db.String(256))
def __init__(self, body):
self.body = body
def __repr__(self):
return "<Post({})>".format(self.id)- In
project/__init__.py
from project.models improt db
app = Flask(__name__)
app.config.from_object(config.DevelopmentConfig)
with app.app_context():
db.init_app()- In
project/config.py:
import os
BASE_DIR = os.path.abspath(os.path.dirname(__name__))
class BaseConfig(object):
# ...
SQLALCHEMY_DATABASE_URI = 'sqlite:///' + os.path.join(BASE_DIR, 'data.db'
SQLALCHEMY_TRACK_MODIFICATIONS = False- Creating the database and interacting with models and queries inside the shell:
>>> from project import app, db
>>> from project.models import Post
>>> app.app_context().push()
>>> db.create_all()
>>> p = Post('Hello!')
>>> db.session.add(p)
>>> db.session.commit()
>>> posts = Post.query.all()- To operate through
$ flask shell, include the following inproject/__init__.py:
from project.models import db, User, Post
@app.shell_context_processor
def make_shell_context():
return {'app': app, 'db': db, 'User': User, 'Post': Post}- For more info on
Flask-SQLAlchemy: official flask-sqlalchemy guide. - For more info on
contexts: official flask-sqlalchemy contexts guide
- Add the following to
project/__init__.py:
from flask_migrate import Migrate
app = Flask(__name__)
app.config.from_object)config.DevelopmentConfig)
migrate = Migrate(app, db)- To initialize the
migrationsfolder:
$ flask db init- To migrate:
$ flask db migrate
- To upgrade:
$ flask db upgrade
- In
models.pyinclude:
from flask_login import LoginManager, UserMixin
login_manager = LoginManager()
@login_manager.user_loader
def load_user(user_id):
return User.get(user_id)- in
project/__init__.pyinclude:
from project.models import login_manager
with app.app_context():
login_manager.init_app(app)-
Although
SQLiteis fine for a simple development server, the databases of production servers are often better suited to a more full-featured DBMS likeMySQL. -
Install
MySQL:
$ sudo apt-get install mysql-server$ sudo mysql_secure_installation- And then:
$ sudo mysql -u root -pCREATE USER 'newuser'@'localhost' IDENTIFIED BY 'password';
GRANT ALL PRIVILEGES ON database_name.* TO 'newuser'@'localhost';$ mysql -u root -pNote: root of MySQL is not the same as the root of the OS.
- Show databases with:
SHOW DATABASES;- Create a database:
CREATE DATABASE database_name;- Establish connection with
SQLAlchemy, installpymysql:
$ pip install pymysql- And within the config object in
config.pyinclude:
SQLALCHEMY_DATABASE_URI = 'mysql+pymysql://root:password@localhost/database';- For more standard commands: the Digital Ocean MySQL tutorial is useful.