Building on the intro Flask taster. You will structure a small app with blueprints, templates, forms, and configuration – enough to grow into the mini project at the end of these tutorials.
Application factory pattern
Create the app in a function so tests and scripts can build it with different settings.
from flask import Flask
def create_app(config=None):
app = Flask(__name__)
app.config.from_mapping(
SECRET_KEY="dev-only-change-me",
DATABASE="sqlite:///app.db",
)
if config:
app.config.update(config)
from .routes import bp as main_bp
app.register_blueprint(main_bp)
return app
Blueprints for organisation
# routes.py
from flask import Blueprint, render_template
bp = Blueprint("main", __name__)
@bp.route("/")
def index():
return render_template("index.html")
@bp.route("/about")
def about():
return render_template("about.html")
Templates with Jinja2
Keep HTML in templates/. Use inheritance so you define layout once.
{# templates/base.html #}
<!doctype html>
<html lang="en-GB">
<head>
<meta charset="utf-8">
<title>{% block title %}My App{% endblock %}</title>
</head>
<body>
<nav><a href="/">Home</a></nav>
{% block content %}{% endblock %}
</body>
</html>
The block above is Jinja2 inside a Python string for the tutorial file. In your project it lives as a .html template file.
Handling forms
from flask import Blueprint, flash, redirect, render_template, request, url_for
bp = Blueprint("contacts", __name__, url_prefix="/contacts")
@bp.route("/new", methods=["GET", "POST"])
def new_contact():
if request.method == "POST":
email = request.form.get("email", "").strip()
if not email:
flash("Email is required.", "error")
else:
save_contact(email)
flash("Contact saved.", "success")
return redirect(url_for("contacts.new_contact"))
return render_template("contacts/new.html")
Flash messages and redirects
After a POST, redirect to a GET. That stops duplicate submissions when the user refreshes the page – the PRG pattern (post/redirect/get).
Static files and url_for
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
Use url_for in templates and Python so renamed routes do not break links.
Running in development
export FLASK_APP=myapp:create_app
export FLASK_DEBUG=1
flask run
Turn debug mode off in production. It exposes an interactive debugger – useful locally, dangerous on the public internet.
Next: scraping responsibly – when it is acceptable, how to be polite to servers, and how not to get blocked or sued.

