Fonctions de vue — afficher la liste des articles et les pages de détail

Dans ce chapitre, vous apprendrez à interroger des données depuis la base de données à l'aide de fonctions de vue, à afficher la page d'accueil et les pages de détail, et à diviser les routes à l'aide de Blueprint.


Les responsabilités des fonctions de vue

Les fonctions de vue Flask ont les mêmes responsabilités que Django :Recevoir la requête → Interroger les données → Rendre le template。

Exemple

# Chemin du fichier : app.py
from flask import Flask, render_template
from models import Post, Category

@app.route("/")
def index():
    """Page d'accueil du blog : affiche tous les articles"""
    posts = Post.query.order_by(Post.created_at.desc()).all()
    categories = Category.query.all()
    return render_template('index.html', posts=posts, categories=categories)

Paramètres de chemin et paramètres de requête

Type de paramètreExemple d'URLComment les vues sont obtenues
Paramètre de chemin/post/3Dans les routes, <type:variable_name> → paramètre de fonction
Paramètre de requête/?category=pythonrequest.args.get('key')

Les routes Flask prennent en charge plusieurs convertisseurs de type :<int:id>(integer),<string:slug>(par défaut, n'inclut pas /),<path:path>(contient /),<float:price>etc.


Page de détail de l'article

Exemple

# Chemin du fichier : app.py append
from flask import abort

@app.route("/post/<int:post_id>")
def post_detail(post_id):
    """Page de détail de l'article"""
    # get_or_404 est équivalent à : Post.query.get(post_id) or abort(404)
    post = Post.query.get_or_404(post_id,
        description=f'L'article #{post_id} n'existe pas')
    return render_template('post_detail.html', post=post)

Page d'erreur 404 personnalisée

Exemple

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

Filtrage par catégorie

Exemple

# Chemin du fichier : refactoriser la vue index dans app.py
from flask import request

@app.route("/")
def index():
    category_slug = request.args.get('category', '')
    keyword = request.args.get('q', '')       # Recherche par mot-clé (implémentée au chapitre 6)

    posts_query = Post.query.order_by(Post.created_at.desc())

    # Filtrer par catégorie
    if category_slug:
        posts_query = posts_query.join(Category).filter(Category.slug == category_slug)

    posts = posts_query.all()
    categories = Category.query.all()

    return render_template('index.html',
        posts=posts, categories=categories,
        category_slug=category_slug, keyword=keyword)

request.argsest un MultiDict immuable, utilisé pour lire les paramètres de requête d'URL. Utilisez.get('key', '默认值')Récupération sécurisée, renvoie une valeur par défaut lorsque le paramètre n'existe pas au lieu de lever une erreur.


Blueprint — découpage des routes

Lorsque les fonctions de vue se multiplient, les empiler toutes dans app.py devient ingérable.

BlueprintC'est le mécanisme de regroupement de routes de Flask : répartir les vues par modules fonctionnels et les enregistrer via app.register_blueprint().

app/
├── blueprints/
│   ├── __init__.py
│   ├── main.py          # 首页、关于、搜索
│   └── posts.py         # 文章列表、详情
├── templates/
├── models.py
└── __init__.py

Exemple

# Chemin du fichier: app/blueprints/main.py
from flask import Blueprint, render_template, request
from app.models import Post, Category

# Blueprint('blueprint_name', __name__, url_prefix='/')
main_bp = Blueprint('main', __name__)

@main_bp.route("/")
def index():
    """Page d'accueil du blog"""
    category_slug = request.args.get('category', '')
    posts_query = Post.query.order_by(Post.created_at.desc())
    if category_slug:
        posts_query = posts_query.join(Category).filter(Category.slug == category_slug)
    return render_template('index.html',
        posts=posts_query.all(),
        categories=Category.query.all(),
        category_slug=category_slug)

Exemple

# Chemin du fichier : app/blueprints/posts.py
from flask import Blueprint, render_template, abort
from app.models import Post

posts_bp = Blueprint('posts', __name__)

@posts_bp.route("/post/<int:post_id>")
def post_detail(post_id):
    post = Post.query.get_or_404(post_id)
    return render_template('post_detail.html', post=post)

Enregistrez le Blueprint au point d'entrée de l'application :

Exemple

# Chemin du fichier : app.py
from flask import Flask
from app.blueprints.main import main_bp
from app.blueprints.posts import posts_bp

app = Flask(__name__)

# Enregistrer les blueprints : toutes les fonctions de vue des blueprints seront fusionnées dans la même application
app.register_blueprint(main_bp)
app.register_blueprint(posts_bp)

Un Blueprint peut spécifierurl_prefix(tel queurl_prefix='/blog'), puis toutes les routes à l'intérieur du blueprint auront automatiquement ce préfixe ajouté. Un Blueprint peut aussi avoir ses propres répertoires de modèles et de fichiers statiques.


Création des modèles pour la page d'accueil et la page de détail

index.html

Exemple

<!-- Chemin du fichier : app/templates/index.html -->
{% extends 'base.html' %}

{% block title %}EXAMPLE Blog - Accueil{% endblock %}

{% block content %}
<h2 class="section-title">Derniers articles</h2>

<!-- Navigation de filtrage par catégorie -->
<div class="category-bar">
    <a href="{{ url_for('main.index') }}"
      class="{% if not category_slug %}active{% endif %}">Toutes</a>
    {% for cat in categories %}
    <a href="{{ url_for('main.index', category=cat.slug) }}"
      class="{% if category_slug == cat.slug %}active{% endif %}">
        {{ cat.name }}
    </a>
    {% endfor %}
</div>

{% if posts %}
<div class="article-grid">
    {% for post in posts %}
    <a href="{{ url_for('posts.post_detail', post_id=post.id) }}" class="card-link">
        <div class="article-card">
            <div class="card-content">
                <span class="card-category">{{ post.category.name }}</span>
                <h3>{{ post.title }}</h3>
                <p>{{ post.summary|truncate(80) }}</p>
                <span class="card-date">{{ post.created_at.strftime('%Y-%m-%d') }}</span>
            </div>
        </div>
    </a>
    {% endfor %}
</div>
{% else %}
<p class="empty-tip">Pas encore d'articles dans cette catégorie.</p>
{% endif %}
{% endblock %}

Lors de l'utilisation d'une vue Blueprint dans url_for(), le format esturl_for('蓝图名.函数名'), tel queurl_for('posts.post_detail', post_id=3). Notez la différence avec celle de Django{% url %}comparaison de balises : Flask utilise{{ url_for() }}, peut être imbriqué dans des expressions Python pour plus de flexibilité.


Résumé du chapitre

Dans ce chapitre, vous avez maîtrisé les vues Flask et l'organisation des routes : Post.query pour interroger les données, paramètre de chemin <int:post_id> et paramètre de requête request.args, get_or_404 pour des requêtes sûres, abort(404) et pages d'erreur personnalisées, et Blueprint pour répartir les routes par module.

Le blog dispose désormais de trois pages complètes : la liste d'articles de la page d'accueil, le filtrage par catégorie et les pages de détail.

autres extensions