Table of Contents
Introduction au modèle de contrôleur de la vue du modèle dans Django
Le modèle de modèle-View-Controller (MVC) est un design architectural qui a tenu le test du temps pour construire des applications web modulaires, maintenables et testables. Alors que Django, le cadre web de haut niveau Python, utilise sa propre terminologie — Modèles, Vues et Modèles — les principes sous-jacents s'harmonisent étroitement avec MVC. En comprenant comment cartographier et étendre ces concepts, vous pouvez créer un code qui est plus facile à raisonner, à étendre et à valider par des tests automatisés.
Cet article explore le modèle MVC en profondeur, montrant comment Django implémente chaque composant et comment vous pouvez appliquer des couches d'abstraction supplémentaires pour garder votre base de code propre et évolutive. Nous allons couvrir les meilleures pratiques pour organiser la logique d'affaires, écrire des tests efficaces, et tirer parti des outils intégrés Django .
Décorer la Triade MVC à Django
Le modèle MVC sépare une application en trois composants interconnectés :
- Modèle — Gère les données et la logique opérationnelle.
- View — Gère la logique de présentation et l'interface utilisateur.
- Contrôleur — Traitement de l'entrée et des coordonnées de l'utilisateur entre Model et View.
Django réinterprète légèrement ces rôles. Son modèle - - correspond directement au modèle MVC. Le - -View- - dans Django agit comme un contrôleur — il reçoit des requêtes HTTP, interroge le modèle et renvoie une réponse. Le -Template- - sert de MVC View, en rendant le HTML (ou d'autres formats de sortie) pour le client.
Calque de modèle Django ,
Django fournit un puissant système de cartographie relationnelle objet (ORM) qui vous permet de définir les modèles de données comme classes Python. Chaque modèle se planifie dans une table de base de données et les instances correspondent à des lignes. En utilisant les champs de modèles Django, vous pouvez définir des colonnes, des relations (ForeignKey, ManyToManyField, OneToOneField) et des contraintes.
Pour garder les modèles propres et ciblés, suivez ces pratiques :
- Conserver la logique d'affaires hors des modèles lorsque c'est possible — Les modèles devraient principalement définir la structure et les relations des données, et non des algorithmes complexes ou des règles de validation qui s'appliquent à plusieurs entités.
- Utilisez des gestionnaires de modèles et des ensembles de requêtes — Encapsuler les requêtes courantes dans des gestionnaires personnalisés.
- Méthodes de modèle de levier pour des opérations simples[ — Des méthodes comme ou le calcul d'une propriété sont acceptables, mais évitent une logique lourde qui interagit avec d'autres modèles.
- Écrire les migrations pour les changements de schéma — Django=s système de migration suit les changements et permet un déploiement sûr dans les environnements.
Django voit comme des contrôleurs
Les vues Django gèrent le rôle du contrôleur : elles acceptent une requête HTTP, effectuent les opérations nécessaires (souvent en interrogeant la base de données à travers des modèles) et renvoient une réponse HTTP. Django prend en charge deux modèles de vue primaires : les vues basées sur les fonctions (FBV) et les vues basées sur les classes (CBV).
Les vues basées sur les fonctions[ sont simples et explicites. Elles sont idéales pour les petits paramètres à usage unique. Cependant, à mesure que votre application grandit, vous pouvez vous retrouver à répéter le code (p. ex., gérer la pagination, énumérer des objets ou valider des formulaires).
Les vues basées sur des classes[ fournissent un comportement générique intégré pour les tâches courantes (ListView, DetailView, CreateView, etc.). Elles encouragent la réutilisation de code par héritage et mixins. Par exemple, une ListView gère automatiquement la pagination, le filtrage des requêtes et le rendu du contexte. Vous pouvez outrepasser des méthodes comme ou pour personnaliser le comportement sans réécrire la plaque de chaudière.
Quelle que soit la configuration choisie, gardez les vues minces. Poussez la logique d'entreprise dans les modules de service, les formulaires ou les fonctions d'utilité.
Modèles comme vues
Le moteur de gabarit Django , qui rend HTML en combinant le balisage statique avec des variables de contexte dynamiques, forme la couche de présentation (le -View , dans le MVC classique). Le système de l'héritage de gabarit Django , qui permet de créer un squelette de base et de l'étendre dans des modèles pour enfants, réduit la redondance et simplifie les modifications de la disposition.
Les meilleures pratiques pour les modèles comprennent :
- Conserver la logique minimale — Les modèles ne doivent contenir que la logique de présentation (en boucle sur les listes, en affichant des éléments sous condition).
- Utilisez des balises et filtres de gabarit personnalisés — Pour le formatage complexe ou les composants d'interface utilisateur réutilisables, créez vos propres balises ou filtres plutôt que de placer la logique dans le modèle.
- Organisez des modèles par app[ — Placez des modèles dans des répertoires nommés d'après l'application (p. ex. ) pour éviter les collisions d'espace de noms.
Création d'une base de codes modulaires avec les applications Django
Chaque projet Django peut être composé de plusieurs applications autonomes, chacune responsable d'un domaine ou d'une fonctionnalité distinct. Par exemple, un site de commerce électronique peut avoir des applications pour , , et . Chaque application encapsule ses propres modèles, vues, modèles, fichiers statiques et tests.
Pour garder les applications vraiment modulaires:
- Définir des limites claires — Une application devrait avoir une responsabilité unique et un couplage minimal avec d'autres applications. Utilisez les signaux Django=s ou les middlewares personnalisés pour communiquer entre les applications sans importation serrée.
- Apps réutilisables[ — Concevez vos applications pour qu'elles puissent être extraites et réutilisées dans d'autres projets. Cela signifie éviter les paramètres codés en dur ou les références directes aux URL racine du projet.
- Utiliser l'injection de dépendance[ — Lorsqu'une application a besoin de quelque chose d'une autre application, passez-la comme paramètre ou utilisez une couche de service qui peut être moquée dans les tests.
Séparer la logique d'affaires : la couche de service
Un module de service contient une logique d'affaires pure, libre de la gestion des requêtes/réponses spécifiques à Django. Cette séparation vous permet de tester des algorithmes critiques sans faire tourner un serveur web ou une base de données (sauf si nécessaire pour la persistance des données).
Par exemple, au lieu d'écrire la logique de traitement dans une vue qui gère un paiement:
def process_payment(request):
# ... fetch user, order
# ... call Stripe API
# ... update order status
return redirect('success')
Vous pouvez déplacer l'interaction Stripe dans un service :
# services/payment_service.py
class PaymentService:
def process(self, user, order, payment_info):
# Stripe API calls, business rules, etc.
# Return result and possibly new order status
pass
Ensuite, la vue appelle simplement le service et gère la réponse. Cette approche rend simple de tester la logique de paiement en midonnant des API externes et des appels de base de données.
Écrire un code testable dans Django
La testabilité est un avantage direct de la séparation MVC propre. Lorsque les composants sont découplés, vous pouvez les tester isolément. Django framework intégré (basé sur Python ) fournit des outils pour créer des tests pour les modèles, les vues, les modèles et les formulaires.
Modèles d'essais unitaires
Les tests de modèle doivent vérifier que votre structure de données et les règles d'entreprise (si aucun intégré dans le modèle) fonctionnent correctement. Utilisez la classe et créez des instances de modèle dans les méthodes de test. Par exemple, testez qu'une méthode de modèle retourne la chaîne attendue, ou qu'une méthode de gestionnaire personnalisée filtre correctement.
from django.test import TestCase
from .models import Product
class ProductModelTest(TestCase):
def test_string_representation(self):
product = Product(name='Test Product')
self.assertEqual(str(product), product.name)
Pour une logique de modèle plus complexe, envisagez d'utiliser pour remplacer les dépendances externes comme l'envoi de courriels ou les appels d'API de tiers.
Vues d'essai (contrôleurs)
Le client de test Django , qui vous permet de simuler les requêtes HTTP et d'examiner les réponses, est idéal pour les tests d'intégration qui vérifient le routage, l'authentification et le rendu des modèles.
Lors du test des vues basées sur les classes, vous pouvez in situer la classe de vue directement (ou utiliser le client de test) et affirmer sur les données contextuelles, les codes d'état et les redirections. Assurez-vous de tester les chemins heureux et les scénarios d'erreur (p. ex., permission refusée, erreurs de validation de formulaire).
Essais de modèles
Pour les balises ou filtres de gabarit complexes, écrivez des tests unitaires dédiés. Djangos et classes vous permettent de rendre une chaîne de gabarit et d'affirmer sur la sortie.
from django.template import Template, Context
from django.test import TestCase
class CustomTagTest(TestCase):
def test_uppercase_filter(self):
t = Template('{% load my_filters %}{{ value|my_upper }}')
c = Context({'value': 'hello'})
self.assertEqual(t.render(c), 'HELLO')
Moqueur et injection de dépendance
Pour écrire des tests d'unité rapides et ciblés, utilisez pour simuler des services externes, des requêtes de base de données, ou même des ORM Django. Par exemple, lorsque vous testez un service qui envoie un courriel, vous vous moquez de la fonction pour éviter la livraison de courriels.
L'injection de dépendance est une autre technique : passer explicitement toutes les dépendances (sessions de base de données, API externes, configuration) à vos fonctions ou constructeurs de classes. Cela facilite la substitution des implémentations réelles par des maquettes.
Meilleures pratiques pour une base de codes propre Django
Au-delà de la cartographie MVC de base, plusieurs techniques aident à maintenir une application Django modulaire et testable:
- Utilisez les signaux intégrés Django=1 avec parcimonie — Les signaux peuvent créer des dépendances cachées et rendre le débogage plus difficile. Préférez les appels explicites aux méthodes de service plutôt qu'une logique axée sur le signal.
- Conserver les URL propres — Organisez les patrons d'URL par application, utilisez des espaces de noms nommés et évitez de mettre une logique complexe dans .
- Le levier de protection pour les préoccupations transversales — L'authentification, l'enregistrement et la validation de la demande sont de bons candidats pour le middleware.
- Ecrire la documentation et les conseils de type — Un code bien documenté avec annotations de type est plus facile à comprendre et à refactorer. Utilisez le module de Python et considérez des outils comme pour l'analyse statique.
- Adopter un style de codage cohérent — Suivre la PEP 8, utiliser des linters (flake8, pylint) et des formateurs (noir, isort). Cela réduit la charge cognitive et rend les examens de code plus fluides.
Exemple du monde réel : Construire un blog avec MVC modulaire à Django
Let , les principes appliqués à une simple application blog. We ,ll définit un modèle , un service pour la création de messages avec validation, une vue de classe pour lister et créer des messages, et un modèle avec héritage.
Modèle [:
from django.db import models
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def get_absolute_url(self):
return reverse('post_detail', args=[self.pk])
Service [:
from .models import Post
class PostService:
def create_post(self, title, content, user):
# business logic: check permissions, validate content length, etc.
if len(content) < 50:
raise ValueError("Content must be at least 50 characters.")
post = Post.objects.create(title=title, content=content, author=user)
return post
Vue ():
from django.views.generic import ListView, CreateView
from django.contrib.auth.mixins import LoginRequiredMixin
from .services import PostService
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'blog/post_list.html'
queryset = Post.objects.filter(published=True)
class PostCreateView(LoginRequiredMixin, CreateView):
model = Post
fields = ['title', 'content']
template_name = 'blog/post_form.html'
def form_valid(self, form):
# Use service to enforce additional rules
service = PostService()
try:
post = service.create_post(
title=form.cleaned_data['title'],
content=form.cleaned_data['content'],
user=self.request.user
)
except ValueError as e:
form.add_error(None, str(e))
return self.form_invalid(form)
return super().form_valid(form)
Template []:
{% extends "base.html" %}
{% block content %}
{% for post in post_list %}
{{ post.title }}
{{ post.content|truncatewords:30 }}
{% endfor %}
{% endblock %}
This structure keeps the view lean, the model focused, and the business logic isolated in a service that can be unit-tested easily.
Tester le service Blog
Voici un test unitaire pour la en utilisant des objets de simulation pour éviter les hits de base de données (vous pouvez également utiliser la base de données de test Django=s pour l'intégration):
from django.test import TestCase
from unittest.mock import patch, MagicMock
from .services import PostService
class PostServiceTest(TestCase):
@patch('blog.services.Post.objects.create')
def test_create_post_short_content_raises_error(self, mock_create):
service = PostService()
with self.assertRaises(ValueError):
service.create_post("Title", "Short", mock_some_user)
mock_create.assert_not_called()
Pour des tests plus approfondis, utilisez Djangos et la base de données réelle pour vérifier que enregistre effectivement le message et que le champ auteur est correctement défini.
Recommandations externes
Pour approfondir votre compréhension de la CVM dans Django et des pratiques de test connexes, explorez ces ressources :
- Django Documentation des couches de modèle — Guide officiel sur les modèles, les champs et les relations.
- Django class-based views documentation[ — Description détaillée des vues génériques et comment les personnaliser.
- Django documentation de test — Couvre le client de test, la base de données de test et les techniques avancées.
- Obey the Testing Goat (Test-Driven Web Development with Python) — Un excellent livre sur la TDD avec Django qui renforce la conception modulaire.
Conclusion
En traitant les modèles Djangos comme la représentation des données, les vues comme contrôleurs et les modèles comme la couche de présentation, vous construisez naturellement une application plus modulaire et testable. Introduire une couche de service découple davantage la logique d'affaires, ce qui facilite l'écriture de tests d'unité rapides et s'adapte aux exigences changeantes.
Avec l'expansion de vos projets, ces principes deviennent encore plus précieux. Une base de code bien structurée Django réduit la dette technique, simplifie l'embarquement pour les nouveaux développeurs et garantit que votre application peut évoluer sans casser en cascade. Embrassez l'esprit de MVC, et vos applications Django seront robustes, durables et prêtes pour les défis de la production.