Codeskill

Learn to code, step by step

Flask beyond hello world

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.

PreviousSQLAlchemy or DB-API structured access