Les Fondamentaux de Django : Modèles, Vues, Templates et URLs
Contexte du cours : Maîtriser Django : Construire des Applications Web Robustes et Scalables avec Python
Introduction à l'Architecture de Django
Bienvenue dans ce cours sur les fondements de Django ! En tant que framework web "Batteries Included", Django excelle dans la facilitation du développement rapide d'applications web robustes et scalables. Au cœur de son fonctionnement se trouve une architecture qui, bien que n'étant pas strictement un modèle MVC (Model-View-Controller) traditionnel, s'en inspire fortement et est souvent décrite comme un modèle MVT (Model-View-Template).
Comprendre les quatre piliers fondamentaux que sont les Modèles, les Vues, les Templates et les URLs est essentiel pour quiconque souhaite maîtriser Django. Ces composants travaillent de concert pour gérer le flux complet d'une requête HTTP, de son arrivée sur le serveur jusqu'à la réponse renvoyée au client.
Dans cette leçon, nous allons explorer chacun de ces piliers en détail, comprendre leur rôle spécifique et voir comment ils s'articulent pour donner vie à vos applications web.
1. Les Modèles (Models) : L'Interaction avec la Base de Données
Qu'est-ce qu'un Modèle ?
Dans Django, un Modèle est la source unique et définitive des informations sur vos données. Il contient les champs et les comportements essentiels des données que vous stockez. Les modèles sont écrits sous forme de classes Python qui héritent de django.db.models.Model.
Le système de modèles de Django est un ORM (Object-Relational Mapper). Il vous permet d'interagir avec votre base de données en utilisant du code Python simple, plutôt que d'écrire du SQL. Cela rend votre code plus lisible, plus maintenable et portable entre différentes bases de données (PostgreSQL, MySQL, SQLite, Oracle, etc.).
Chaque attribut de la classe Modèle représente un champ de la base de données. Django fournit une multitude de types de champs (texte, nombre entier, date, booléen, relation, etc.) pour couvrir tous vos besoins.
Définir un Modèle
Un modèle est généralement défini dans le fichier models.py d'une application Django.
Considérons un exemple simple pour une application de blog où nous voulons stocker des articles :
# blog/models.py
from django.db import models
from django.utils import timezone # Pour les dates
class Article(models.Model):
titre = models.CharField(max_length=200)
contenu = models.TextField()
date_publication = models.DateTimeField(default=timezone.now)
est_publie = models.BooleanField(default=True)
class Meta:
# Optionnel: Ordonner les articles par date de publication décroissante par défaut
ordering = ['-date_publication']
# Optionnel: Nom lisible pour le modèle dans l'interface d'administration
verbose_name = "Article de Blog"
verbose_name_plural = "Articles de Blog"
def __str__(self):
# Cette méthode est appelée lorsque vous affichez un objet Article
# Elle est utile pour le débogage et l'affichage dans l'interface d'administration
return self.titre
Explication du Code :
from django.db import models: Importe le modulemodelsnécessaire.class Article(models.Model):: Définit notre modèleArticlequi hérite demodels.Model.titre = models.CharField(max_length=200): Crée un champ de texte de petite taille (maximum 200 caractères).contenu = models.TextField(): Crée un champ de texte de grande taille, adapté aux corps d'articles.date_publication = models.DateTimeField(default=timezone.now): Un champ de date et heure.default=timezone.nowsignifie que la date et l'heure actuelles seront automatiquement définies lors de la création d'un nouvel article si non spécifié.est_publie = models.BooleanField(default=True): Un champ booléen (Vrai/Faux) avec une valeur par défaut deTrue.class Meta:: Une classe interne optionnelle pour définir des métadonnées sur le modèle (ordre par défaut, noms lisibles, etc.).def __str__(self):: Une méthode Python standard qui définit la représentation textuelle de l'objet. C'est très utile pour l'affichage des objets dans le shell Django ou l'interface d'administration.
Migrations
Après avoir défini ou modifié vos modèles, vous devez les "migrer" vers la base de données. Django utilise un système de migrations qui crée et met à jour le schéma de votre base de données.
-
Créer les migrations :
python manage.py makemigrations blogCette commande examine les changements dans vos
models.pyet crée des fichiers de migration Python (.py) qui décrivent ces changements. -
Appliquer les migrations :
python manage.py migrateCette commande exécute les migrations non appliquées et met à jour votre base de données pour qu'elle corresponde à la définition de vos modèles.
2. Les Vues (Views) : La Logique Métier
Qu'est-ce qu'une Vue ?
Une Vue est une fonction ou une classe Python qui reçoit une requête web (un objet HttpRequest) et retourne une réponse web (un objet HttpResponse). C'est le cœur de la logique métier de votre application.
Les vues sont responsables de :
- Récupérer des données des modèles.
- Traiter ces données (filtrer, trier, modifier).
- Rendre un template HTML avec les données traitées.
- Gérer les formulaires et les requêtes HTTP (GET, POST, etc.).
- Retourner des réponses HTTP (HTML, JSON, redirections, erreurs 404, etc.).
Django distingue les vues basées sur des fonctions (FBV) et les vues basées sur des classes (CBV). Pour commencer, nous nous concentrerons sur les FBV car elles sont plus simples à appréhender.
Définir une Vue
Les vues sont généralement définies dans le fichier views.py d'une application Django.
Reprenons notre exemple de blog et créons une vue qui affichera la liste de tous les articles :
# blog/views.py
from django.shortcuts import render # Permet de rendre un template HTML
from .models import Article # Importe notre modèle Article
def liste_articles(request):
# 1. Récupérer les données des modèles
# On récupère tous les articles qui sont publiés
articles = Article.objects.filter(est_publie=True)
# 2. Préparer le contexte (les données à passer au template)
context = {
'articles': articles
}
# 3. Rendre le template avec le contexte
return render(request, 'blog/liste_articles.html', context)
def detail_article(request, article_id):
# Récupère un article par son ID, ou lève une 404 si non trouvé
article = Article.objects.get(id=article_id)
context = {
'article': article
}
return render(request, 'blog/detail_article.html', context)
Explication du Code :
from django.shortcuts import render:renderest une fonction raccourcie très utile qui prend la requête, le chemin vers un template et un dictionnaire de contexte, puis retourne un objetHttpResponseavec le template rendu.from .models import Article: Importe notre modèleArticledepuis le même répertoire (.).def liste_articles(request):: Définit notre vue. Elle prend toujours un argumentrequestqui est un objetHttpRequest.articles = Article.objects.filter(est_publie=True): C'est l'interface ORM de Django.Article.objectsest le gestionnaire par défaut qui nous permet de faire des requêtes sur notre modèle.filter(est_publie=True)sélectionne tous les articles où le champest_publieestTrue.context = {'articles': articles}: Un dictionnaire Python qui contient les données que nous voulons rendre disponibles dans notre template. La clé ('articles') sera le nom de la variable dans le template.return render(request, 'blog/liste_articles.html', context): Retourne la réponse HTTP. Django cherchera le templateblog/liste_articles.htmldans les répertoirestemplatesconfigurés, lui passera le dictionnairecontextet renverra le HTML généré.
3. Les Templates (Templates) : La Présentation des Données
Qu'est-ce qu'un Template ?
Les Templates sont des fichiers qui contiennent le code HTML de votre application, mélangé avec la syntaxe du Django Template Language (DTL). Ils sont utilisés pour séparer la logique de présentation des données de la logique métier (qui est dans les vues).
Le DTL permet d'insérer des variables, d'exécuter des boucles, des conditions et d'inclure d'autres templates, le tout sans introduire de logique Python complexe.
Utiliser un Template
Après qu'une vue ait récupéré et préparé les données, elle les passe à un template pour l'affichage.
Créons les templates liste_articles.html et detail_article.html que nous avons référencés dans nos vues.
Pour que Django trouve vos templates, il est courant de créer un dossier templates à la racine de votre application, et d'y créer un sous-dossier avec le nom de votre application pour éviter les conflits (ex: blog/templates/blog/).
blog/templates/blog/liste_articles.html :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Liste des Articles</title>
</head>
<body>
<h1>Bienvenue sur notre Blog !</h1>
{% if articles %} {# Balise de condition: Si la liste 'articles' n'est pas vide #}
<ul>
{% for article in articles %} {# Balise de boucle: Pour chaque article dans la liste #}
<li>
<h2><a href="/articles/{{ article.id }}/">{{ article.titre }}</a></h2> {# Accès aux attributs de l'objet #}
<p>{{ article.date_publication|date:"d M Y" }}</p> {# Utilisation d'un filtre pour formater la date #}
<p>{{ article.contenu|truncatechars:150 }}...</p> {# Filtre pour tronquer le contenu #}
</li>
{% endfor %}
</ul>
{% else %}
<p>Aucun article n'est disponible pour le moment.</p>
{% endif %}
</body>
</html>
blog/templates/blog/detail_article.html :
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ article.titre }}</title>
</head>
<body>
<a href="/articles/">Retour à la liste</a>
<h1>{{ article.titre }}</h1>
<p><em>Publié le : {{ article.date_publication|date:"d M Y à H:i" }}</em></p>
<div>
{{ article.contenu|linebreaksbr }} {# Filtre pour les sauts de ligne #}
</div>
</body>
</html>
Explication du Code :
Le DTL utilise deux types principaux de délimiteurs :
-
{{ variable }}: Affiche la valeur d'une variable. -
{% tag %}: Exécute une logique (boucles, conditions, chargement d'autres templates). -
{{ article.titre }}: Accède à l'attributtitrede l'objetarticlepassé par le contexte. -
{% if articles %}et{% endif %}: Des balises de flux de contrôle pour les conditions. -
{% for article in articles %}et{% endfor %}: Des balises de flux de contrôle pour les boucles. -
{{ article.date_publication|date:"d M Y" }}: Utilise un filtre. Les filtres sont des fonctions qui transforment la valeur d'une variable. Ici,date:"d M Y"formate la date. -
{{ article.contenu|truncatechars:150 }}: Un autre filtre pour tronquer le texte à 150 caractères. -
{{ article.contenu|linebreaksbr }}: Convertit les retours à la ligne (\n) en balises<br>HTML. -
{# Commentaire #}: Pour les commentaires qui ne seront pas affichés dans le HTML final.
Le DTL est conçu pour être simple et sécurisé, empêchant l'exécution de code Python arbitraire directement dans les templates, ce qui garantit la séparation des préoccupations.
4. Les URLs (URLs) : Le Routage des Requêtes
Qu'est-ce qu'une URL ?
Le système d'URLs de Django est un répartiteur (dispatcher) qui mappe les requêtes web entrantes à leurs vues correspondantes. Chaque URL est associée à une vue spécifique, et c'est le rôle du répartiteur d'URLs de déterminer quelle vue doit être appelée pour une URL donnée.
Ce système est défini dans des fichiers urls.py. Il existe généralement un fichier urls.py principal au niveau du projet, et des fichiers urls.py secondaires au niveau de chaque application pour une meilleure modularité.
Définir les URLs
-
Au niveau de l'application (
blog/urls.py) : Créez un fichierurls.pydans le répertoire de votre applicationblog.# blog/urls.py from django.urls import path from . import views # Importe toutes les vues de l'application blog app_name = 'blog' # Permet de nommer l'application pour les URLs inversées urlpatterns = [ path('', views.liste_articles, name='liste'), # URL pour la page d'accueil du blog path('articles/<int:article_id>/', views.detail_article, name='detail'), # URL pour le détail d'un article ] -
Au niveau du projet (
monprojet/urls.py) : Vous devez inclure les URLs de votre application dans le fichierurls.pyprincipal de votre projet.# monprojet/urls.py (fichier principal du projet) from django.contrib import admin from django.urls import path, include # Importe 'include' pour inclure les URLs d'applications urlpatterns = [ path('admin/', admin.site.urls), # URL pour l'interface d'administration Django path('articles/', include('blog.urls')), # Inclut les URLs de l'application blog sous le préfixe 'articles/' ]
Explication du Code :
from django.urls import path, include: Importe les fonctions nécessaires pour définir les chemins d'URLs.urlpatterns = [...]: C'est la liste principale des patterns d'URLs. Django parcourt cette liste dans l'ordre pour trouver une correspondance avec l'URL de la requête.path('admin/', admin.site.urls): Un pattern pour l'interface d'administration de Django.admin.site.urlsest une URLconf prédéfinie.path('articles/', include('blog.urls')): C'est ici que nous incluons les URLs de notre applicationblog. Toute URL qui commence par/articles/sera ensuite gérée par le fichierblog/urls.py. Par exemple, si l'utilisateur va sur/articles/, c'est la vueliste_articlesqui sera appelée. Si c'est/articles/123/, c'estdetail_articleavecarticle_id=123.path('', views.liste_articles, name='liste'):- Le premier argument
''(chaîne vide) signifie que ce pattern correspondra à la racine de ce niveau d'inclusion (donc/articles/). - Le deuxième argument
views.liste_articlesest la vue à appeler lorsque ce pattern correspond. name='liste': Donne un nom à ce pattern d'URL. C'est extrêmement utile pour générer des URLs de manière dynamique dans vos templates ou vues sans avoir à les "coder en dur" (principe de "DRY" - Don't Repeat Yourself). On peut y faire référence avec{% url 'blog:liste' %}dans un template, par exemple.
- Le premier argument
path('articles/<int:article_id>/', views.detail_article, name='detail'):articles/<int:article_id>/: Définit un chemin qui inclut un paramètre variable.<int:article_id>capture une valeur entière (spécifiée parint:) et la passe à la vuedetail_articlecomme argument nomméarticle_id.name='detail': Nomme ce pattern, utilisable comme{% url 'blog:detail' article.id %}.
app_name = 'blog': Définit un namespace pour les URLs de cette application. Cela est crucial lorsque vous avez plusieurs applications avec des noms d'URL similaires. Par exemple, si vous avez une applicationproduitsavec une URLdetail, vous pouvez la distinguer de l'URLdetailde l'applicationblogen utilisant{% url 'blog:detail' ... %}et{% url 'produits:detail' ... %}.
5. L'Interaction des Composants : Le Cycle de Requête/Réponse
Maintenant que nous avons examiné chaque composant individuellement, voyons comment ils interagissent dans le flux d'une requête web typique dans Django.
-
Requête HTTP : Un utilisateur tape une URL dans son navigateur (ex:
http://localhost:8000/articles/) et envoie une requête HTTP à votre application Django. -
URLs (Routage) :
- Le serveur web (souvent via un serveur WSGI comme Gunicorn ou uWSGI en production, ou le serveur de développement de Django) reçoit la requête.
- Django examine l'URL demandée et la compare aux
urlpatternsdéfinis dans votre fichierurls.pyprincipal (monprojet/urls.py). - Si une correspondance est trouvée (par exemple,
/articles/correspond àinclude('blog.urls')), Django délègue la requête au fichierurls.pyde l'applicationblog. - Dans
blog/urls.py,''correspond à la vueliste_articles. Django identifie la vue à appeler et lui passe l'objetHttpRequest.
-
Vues (Logique Métier) :
- La fonction
liste_articles(request)dansblog/views.pyest appelée. - La vue interagit avec le Modèle pour récupérer les données nécessaires. Dans notre cas,
articles = Article.objects.filter(est_publie=True). L'ORM de Django traduit cette requête Python en SQL et l'exécute sur la base de données. - La base de données renvoie les données (les articles publiés).
- La vue prépare un dictionnaire de
contextcontenant ces données.
- La fonction
-
Templates (Rendu de la Présentation) :
- La vue appelle
render(request, 'blog/liste_articles.html', context). - Le moteur de templates de Django prend le fichier
blog/liste_articles.html. - Il insère les données du
context(notre liste d'articles) dans le template, exécute les boucles ({% for %}) et les conditions ({% if %}), et applique les filtres (|date,|truncatechars). - Le résultat est une chaîne de caractères HTML pure.
- La vue appelle
-
Réponse HTTP :
- La fonction
renderencapsule cette chaîne HTML dans un objetHttpResponse. - Cet objet
HttpResponseest renvoyé par la vue. - Django transmet cette réponse au serveur web, qui l'envoie finalement au navigateur de l'utilisateur.
- La fonction
-
Affichage par le Navigateur : Le navigateur reçoit le HTML et l'affiche à l'utilisateur.
Ce cycle se répète pour chaque requête, garantissant une séparation claire des responsabilités et une maintenance facilitée de votre code.
Conclusion
Nous avons parcouru les quatre piliers fondamentaux de Django : les Modèles, les Vues, les Templates et les URLs.
- Les Modèles définissent la structure de vos données et l'interface avec la base de données via l'ORM de Django, permettant une manipulation facile des données en Python.
- Les Vues encapsulent la logique métier, traitent les requêtes HTTP, interagissent avec les modèles pour obtenir des données et préparent le contexte pour les templates.
- Les Templates gèrent la présentation visuelle, utilisant le Django Template Language pour afficher les données de manière dynamique sans mélanger la logique de présentation et la logique métier.
- Les URLs agissent comme le système de routage, dirigeant les requêtes entrantes vers les vues appropriées en fonction des motifs d'URL définis.
Comprendre comment ces composants interagissent est la clé pour construire des applications Django robustes et maintenables. Cette architecture MVT favorise la séparation des préoccupations, ce qui rend le développement plus organisé, le débogage plus simple et la collaboration en équipe plus efficace. Vous êtes maintenant prêt à commencer à construire vos propres applications web avec Django !