Doing it all as an app
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.
Directoryflaskapp/
Directorystatic/
- style.css
Directorytemplates/
- index.html
- base.html
__init__.py- blog.py
- db.py
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.
from flask import Flaskimport contextlibimport 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. -
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 runAdding the blog blueprint
Create a new file called blog.py and add the following code to it.
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.
# 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.
from flask import Flaskfrom flask_sqlalchemy import SQLAlchemyfrom 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 databases -
The
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.
# 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.
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"