Doing it all as an app
A simple website built using flask
While blueprints are good for organising the code things will start to get messy as the app grows. We can use python modules to create a more organised structure.
- flaskapp/
- static/
- style.css
- templates/
- index.html
- base.html
__init__.py- blog.py
- db.py
- static/
Most Python projects use this structure to organise their code and should be used as for all your projects.
Creating the app
Create a new folder called flaskapp and add a __init__.py file to it. This file will be the entry point for the app.
// flaskapp/__init__.py
from flask import Flask
import contextlib
import os
def create_app(test_config=None) -> Flask:
app = Flask(__name__)
app.config.from_mapping(
SECRET_KEY="dev",
DATABASE=os.path.join(app.instance_path, "flaskapp.sqlite"),
)
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile("config.py", silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
with contextlib.suppress(OSError):
os.makedirs(app.instance_path)
@app.route("/ping")
def ping() -> str:
return "pong!"
return app
The
create_appfunction creates a new Flask appThis function is automatically called by Flask when the app is run. It accepts an optional
test_configparameter which can be used to pass in configuration values.Config is set
The app is configured with a
SECRET_KEYand aDATABASEpath. TheSECRET_KEYis used by Flask and extensions to keep data safe. TheDATABASEis the path where the SQLite database file will be stored.If this were ever going to be run in production or as a normal application the secret key should be very secure and not just
DEV.A method to load external configuration
The
config.pyfile in the instance folder can be used to set configuration values. This is useful for setting values that should not be in version control.The
instancefolder is createdThe
instancefolder is created if it does not exist. This folder is used to store files that should not be in version control.with contextlib.suppress(OSError):is used to suppress the error if the folder already exists. This is similar to atryandexceptblock.A ping route is added
A simple route is added to check if the app is running. When the
/pingroute is accessed, the app will returnpong!.
Running the app
To run our app we can run:
flask --app flaskapp run
We can also run the app in debug mode by adding --debug to the end.
Adding the blog blueprint
Create a new file called blog.py and add the following code to it.
// flaskapp/blog.py
from flask import Blueprint
blog = Blueprint('blog', __name__)
@blog.route('/')
def index():
return 'Hello from the blog'
This blueprint will be used to handle all the blog related routes.
Registering the blueprint
Update the __init__.py file to register the blueprint.
// flaskapp/__init__.py
# ensure the instance folder exists
with contextlib.suppress(OSError):
os.makedirs(app.instance_path)
+ from .blog import blog
+ app.register_blueprint(blog)
@app.route("/ping")
def ping() -> str:
return "pong!"
Setting up the database
Following from how we set up the blog blueprint, we can create a new file called db.py and add the following code to it.
// flaskapp/db.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from sqlalchemy.orm import DeclarativeBase
class Base(DeclarativeBase):
pass
db = SQLAlchemy(model_class=Base)
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100), nullable=False)
content = db.Column(db.Text, nullable=False)
def init_app(app: Flask):
db.init_app(app)
with app.app_context():
db.create_all()
The
Baseclass is created as a base for the databasesThe
dbobject is createdThe
dbobject is created using theSQLAlchemyclass. Themodel_classparameter is set to theBaseclass to use it as the base for all models.The
Postmodel is createdThe
Postmodel is created with anid,title, andcontentcolumn. Theidcolumn is the primary key. Thetitleandcontentcolumns are set to be not nullable.The
init_appfunction is createdThe
init_appfunction is created to initialise the database. Thedbobject is initialised with the app. The database is created with thecreate_allmethod.
In the __init__.py file, import the db module and call the init_app function.
// flaskapp/__init__.py
# ensure the instance folder exists
with contextlib.suppress(OSError):
os.makedirs(app.instance_path)
+ from .db import init_app
+ init_app(app)
from .blog import blog
app.register_blueprint(blog)
With the database set up, we can now add a route to add a post to the database.
// flaskapp/blog.py
+ from .db import Post, db
...
+@bp.route("/add_post")
+def add_post():
+ post = Post(title="Hello World", content="This is my first post")
+ db.session.add(post)
+ db.session.commit()
+ return "Post added"