Aller au contenu principal

11.1 — Introduction to Flask

Theory 45 min Intermediate

What is Flask?

Flask is a lightweight Python micro-framework for building web applications and REST APIs. Created by Armin Ronacher in 2010, it deliberately stays minimal — providing routing, request handling, and templating without forcing an ORM, authentication library, or form validator. You add only what you need.

┌─────────────────────────────────────────────────────┐
│ Flask Architecture │
│ │
│ Browser/Client │
│ │ HTTP Request │
│ ▼ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ Flask App │──▶│ URL Router │ │
│ │ (WSGI) │ │ (url_map) │ │
│ └─────────────┘ └──────┬───────┘ │
│ │ match │
│ ┌──────▼───────┐ │
│ │ View Func │ │
│ │ (Python fn) │ │
│ └──────┬───────┘ │
│ ┌────────────────┼─────────────┐ │
│ ▼ ▼ ▼ │
│ ┌────────────┐ ┌──────────────┐ ┌────────┐ │
│ │ Jinja2 │ │ JSON/Data │ │ DB │ │
│ │ Templates │ │ (REST API) │ │ Query │ │
│ └────────────┘ └──────────────┘ └────────┘ │
│ │ │
│ ▼ │
│ HTTP Response ──▶ Browser/Client │
└─────────────────────────────────────────────────────┘

Installation & First App

mkdir flask-project && cd flask-project
python3 -m venv venv
source venv/bin/activate # Windows: venv\Scripts\activate
pip install flask

Create app.py:

from flask import Flask

app = Flask(__name__) # __name__ tells Flask where to find resources

@app.route("/") # URL pattern
def home():
return "Hello, Flask!" # Response body (plain text)

@app.route("/about")
def about():
return "<h1>About Page</h1><p>Built with Flask.</p>"

if __name__ == "__main__":
app.run(debug=True) # debug=True: auto-reload + detailed errors
python3 app.py
# → Running on http://127.0.0.1:5000

Important: Never use debug=True in production. It exposes an interactive debugger.


Routing

URL Patterns and Variables

from flask import Flask

app = Flask(__name__)

# Static routes
@app.route("/users")
def users():
return "User list"

# Dynamic segments — <variable_name>
@app.route("/users/<int:user_id>")
def get_user(user_id): # Flask injects the captured value
return f"User #{user_id}"

@app.route("/users/<string:username>")
def profile(username):
return f"Profile: {username}"

# Slug with slashes
@app.route("/docs/<path:subpath>")
def docs(subpath):
return f"Docs path: {subpath}"

Converters: string (default), int, float, path (allows /), uuid

HTTP Methods

By default, routes only accept GET. Use the methods parameter:

from flask import Flask, request, redirect, url_for

@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form.get("username")
password = request.form.get("password")
# validate…
return redirect(url_for("dashboard")) # PRG pattern
return """
<form method="POST">
<input name="username" placeholder="Username">
<input name="password" type="password" placeholder="Password">
<button type="submit">Login</button>
</form>
"""

@app.route("/dashboard")
def dashboard():
return "Welcome to the dashboard!"

url_for() generates URLs by function name — if you change a URL pattern, links auto-update.


The Request Object

Flask's global request object exposes everything about the incoming HTTP request:

from flask import request

@app.route("/search")
def search():
# Query parameters: /search?q=python&page=2
q = request.args.get("q", "") # default "" if missing
page = request.args.get("page", 1, type=int)

# Form data (POST with Content-Type: application/x-www-form-urlencoded)
# request.form.get("field_name")

# JSON body (POST with Content-Type: application/json)
# data = request.get_json()

# File uploads
# f = request.files.get("upload")

# Headers
ua = request.headers.get("User-Agent", "unknown")

return f"Searching '{q}', page {page}, UA: {ua}"

Jinja2 Templates

Instead of returning raw HTML strings, use Jinja2 templates (Flask includes it by default).

Project structure

flask-project/
├── app.py
├── templates/
│ ├── base.html
│ └── index.html
└── static/
├── style.css
└── logo.png

templates/base.html — layout template

<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<nav>
<a href="{{ url_for('home') }}">Home</a>
<a href="{{ url_for('about') }}">About</a>
</nav>

<main>
{% block content %}{% endblock %} {# child templates fill this block #}
</main>

<footer>© 2025 My Flask App</footer>
</body>
</html>

templates/index.html — child template

{% extends "base.html" %}

{% block title %}Home{% endblock %}

{% block content %}
<h1>Welcome, {{ username }}!</h1>

{% if items %}
<ul>
{% for item in items %}
<li>{{ item.name }} — ${{ item.price | round(2) }}</li>
{% endfor %}
</ul>
{% else %}
<p>No items found.</p>
{% endif %}
{% endblock %}

Rendering templates in Python

from flask import Flask, render_template

@app.route("/")
def home():
products = [
{"name": "Laptop", "price": 999.99},
{"name": "Keyboard", "price": 49.95},
]
return render_template("index.html",
username="Alice",
items=products)

Key Jinja2 syntax:

SyntaxPurpose
{{ variable }}Output a value (auto-escaped for XSS safety)
{% if %}…{% endif %}Conditional block
{% for x in list %}…{% endfor %}Loop
{% extends "base.html" %}Template inheritance
{% block name %}…{% endblock %}Overrideable block
{{ value | filter }}Apply a filter (e.g., upper, round, length)

Static Files

Place assets in the static/ folder:

# In templates: url_for('static', filename='style.css')
# Generates: /static/style.css

# In Python:
from flask import send_from_directory

@app.route("/downloads/<filename>")
def download(filename):
return send_from_directory("downloads", filename, as_attachment=True)

Response Objects

from flask import make_response, jsonify, redirect, url_for

# Custom headers & cookies
@app.route("/cookie")
def set_cookie():
resp = make_response("Cookie set!")
resp.set_cookie("session_id", "abc123", httponly=True, samesite="Lax")
return resp

# JSON response
@app.route("/api/status")
def status():
return jsonify({"status": "ok", "version": "1.0"}) # sets Content-Type: application/json

# Redirect
@app.route("/old-url")
def old_url():
return redirect(url_for("home"), code=301) # permanent redirect

# Custom status code
@app.route("/forbidden")
def forbidden():
return "Access denied", 403

Error Handlers

@app.errorhandler(404)
def not_found(error):
return render_template("404.html"), 404

@app.errorhandler(500)
def server_error(error):
return jsonify({"error": "Internal server error"}), 500

Key Vocabulary

TermDefinition
RouteURL pattern mapped to a Python function
View functionPython function that handles a request and returns a response
WSGIWeb Server Gateway Interface — Python web standard
Jinja2Flask's templating engine
Template inheritanceBase + child template pattern to avoid duplication
url_for()Helper that generates URLs by function name
requestThread-local global object with all HTTP request data
debug=TrueAuto-reload and interactive debugger (dev only!)

Summary

  • Flask(__name__) creates the application
  • @app.route("/path", methods=["GET","POST"]) maps URLs to functions
  • <int:id> captures and converts dynamic URL segments
  • request.args, request.form, request.get_json() access request data
  • render_template("file.html", key=value) renders Jinja2 templates
  • url_for("function_name") generates safe, dynamic URLs
  • jsonify({...}) returns JSON responses with the correct Content-Type

Next: 11.2 — REST APIs with Flask to build professional JSON APIs.