Refactorisation de la vue basée sur les classes (CBV)

Dans ce chapitre, vous allez apprendre les vues basées sur les classes (CBV) de Django et refactoriser la page d'accueil et la page de détail avec un code plus concis.


FBV vs CBV

Jusqu'à présent, toutes nos vues ont été écrites à l'aide de fonctions (vues basées sur les fonctions, FBV).

Django fournit égalementles vues basées sur les classes (CBV), qui utilisent des classes pour encapsuler la logique des vues.

FonctionnalitésFBV (vue basée sur les fonctions)CBV (vues basées sur les classes)
volume de codeFlexible, mais la logique commune doit être écrite de façon répétéeAprès avoir hérité de la vue générique, seules quelques lignes de code sont nécessaires
LisibilitéDéroulement linéaire, logique claireLa chaîne d'héritage demande un suivi, mais une fois maîtrisée, elle est évidente au premier regard.
RéutilisabilitéEncapsulé via des fonctionsUtilisation de la composition de Mixin (une marque de fabrique de Django)
Scénarios applicablesPages avec une logique simple et un déroulement clairPages récurrentes telles que créer, lire, mettre à jour, supprimer (CRUD)
Répartition des méthodes HTTPManuel : if request.method == 'POST'Répartition automatique vers les méthodes get() / post()

Il n'y a ni avantage ni inconvénient absolu entre les deux ; les projets Django généralement...Mélanger FBV et CBV: Utilisez FBV pour la logique complexe, et CBV pour le CRUD standard.


ListView — refactorisation de la page de liste

La vue index de la page d'accueil consiste essentiellement à :Interroger la liste des articles → rendre le template。

Pour ce genre de logique récurrente, Django...ListViewDéjà écrit pour vous.

Exemple

# Chemin du fichier : blog/views.py
from django.views.generic import ListView
from django.db.models import Q
from .models import Post, Category

class PostListView(ListView):
    """Page d'accueil du blog : hérite de ListView, affiche la liste des articles"""
    model = Post                           # Spécifier le modèle
    template_name = 'blog/index.html'       # Spécifier le gabarit (par défaut : blog/post_list.html)
    context_object_name = 'posts'           # Nom de la variable utilisée dans le gabarit (par défaut : object_list)
    paginate_by = 12                        # 12 éléments par page (pagination)
    ordering = ['-created_at']             # Tri

    def get_queryset(self):
        """Redéfinir la méthode de requête : prend en charge le filtrage par catégorie + la recherche par mot-clé"""
        queryset = super().get_queryset()

        # Filtre de catégorie
        self.category_slug = self.request.GET.get('category', '')
        if self.category_slug:
            queryset = queryset.filter(category__slug=self.category_slug)

        # Recherche par mot-clé
        self.keyword = self.request.GET.get('q', '')
        if self.keyword:
            queryset = queryset.filter(
                Q(title__icontains=self.keyword) |
                Q(summary__icontains=self.keyword)
            )

        return queryset

    def get_context_data(self, **kwargs):
        """Surcharger la méthode de contexte : injecter des données supplémentaires dans le template"""
        context = super().get_context_data(**kwargs)
        context['categories'] = Category.objects.all()
        context['category_slug'] = self.category_slug
        context['keyword'] = self.keyword
        context['title'] = 'EXAMPLE Blog - Accueil'
        return context

Comparez le volume de code avant et après refactorisation : FBV fait environ 40 lignes → CBV fait environ 30 lignes, et la logique est clairement divisée en différentes méthodes.


DetailView — refactorisation de la page de détail

Exemple

# Chemin du fichier: blog/views.py (nouvellement ajouté)
from django.views.generic import DetailView

class PostDetailView(DetailView):
    """Page de détail d'article : hérite de DetailView"""
    model = Post
    template_name = 'blog/post_detail.html'
    context_object_name = 'post'

    # pk_url_kwarg : nom du paramètre pour transmettre la clé primaire dans l'URL (par défaut, pk ; déclaré explicitement ici).
    pk_url_kwarg = 'pk'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['title'] = f'{self.object.title} - Blog d'EXEMPLE'
        return context

Mettre à jour la configuration des routes

La syntaxe de routage des CBV est légèrement différente de celle des FBV — elle nécessite d'appeler....as_view()。

Exemple

# Chemin du fichier : blog/urls.py
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views

url = [
    # CBV : ajoutez .as_view() après la classe pour la convertir en une fonction de vue
    path('', views.PostListView.as_view(), name='index'),
    path('post/<int:pk>/', views.PostDetailView.as_view(), name='post_detail'),

    # Les autres vues restent inchangées
    path('register/', views.register, name='register'),
    path('login/', auth_views.LoginView.as_view(
        template_name='blog/login.html',
        redirect_authenticated_user=True
    ), name='login'),
    path('logout/', auth_views.LogoutView.as_view(), name='logout'),
    path('post/<int:pk>/favorite/', views.toggle_favorite, name='toggle_favorite'),
]

Pourquoi utiliser des CBV ?.as_view()? La configuration d'URL de Django attend un objet appelable (une fonction)..as_view()Il convertit la vue de classe en un objet appelable qui est conforme à la signature de fonction de vue de Django, et gère en interne la répartition automatique vers la méthode get() ou post() de la classe en fonction de la méthode HTTP (GET/POST).


Aperçu des vues génériques courantes

vueNom du gabarit par défautObjectif
ListViewmodelname_list.htmlAfficher la liste des objets
DetailViewmodelname_detail.htmlAfficher les détails d'un objet unique
CreateViewmodelname_form.htmlCréer un nouvel objet (avec formulaire)
UpdateViewmodelname_form.htmlMettre à jour un objet existant
DeleteViewmodel_name_confirm_delete.htmlConfirmer la suppression de l'objet
TemplateViewil faut spécifierRendre un template statique (aucune requête de données)

Les vues génériques de Django couvrent environ 80% des scénarios de développement web. Lorsque vous rencontrez des situations qui ne répondent pas à vos besoins, revenez aux FBV.


LoginRequiredMixin

CBV non disponible@login_requiredDécorateurs (ceux-ci sont destinés aux fonctions), passez à...LoginRequiredMixin。

Exemple

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView

class FavoriteListView(LoginRequiredMixin, ListView):
    """Liste des favoris : connexion requise pour accéder"""
    model = Post
    template_name = 'blog/favorites.html'
    context_object_name = 'posts'
    ordering = ['-created_at']

    # LoginRequiredMixin : les utilisateurs non authentifiés seront automatiquement redirigés vers settings.LOGIN_URL

    def get_queryset(self):
        # Afficher uniquement les articles mis en favori par l'utilisateur actuel
        return self.request.user.favorite_posts.all().order_by('-created_at')

L'ordre d'héritage des Mixins est très important :LoginRequiredMixinDoit être écrit dansListViewPlus tôt. L'ordre de résolution de l'héritage multiple de Python va de gauche à droite ; LoginRequiredMixin vérifie d'abord l'état de connexion, et ce n'est qu'après validation qu'il poursuit l'exécution de la logique de ListView.


Quand utiliser CBV, et quand utiliser FBV ?

Règle empirique :

  • FBV: Vues avec une logique complexe, de nombreuses branches conditionnelles et des flux non standard (comme toggle_favorite)
  • CBV: Vues avec des opérations CRUD standard et une logique pouvant être clairement scindée en get/post (comme les pages de liste, les pages de détail)

Les opérations comme toggle_favorite (bascule des favoris) ont une logique simple mais un flux différent du CRUD conventionnel ; FBV est plus approprié.

Pour les pages d'affichage de données standard comme index et post_detail, CBV peut réduire considérablement le code passe-partout.


Résumé du chapitre

Dans ce chapitre, vous avez appris l'utilisation essentielle des vues basées sur des classes de Django : ListView affiche des listes, DetailView affiche des détails, get_queryset/get_context_data personnalisent les requêtes et le contexte, as_view() active le routage, et LoginRequiredMixin remplace login_required.

Le code refactorisé de la page d'accueil et de la page de détail est plus court et a une structure plus claire.

autres extensions