Django 6.0
🎯 Objectif : maîtriser Django 6.0 au point de livrer un CRUD complet (modèles, vues, admin, API REST) en quelques jours.
À l'issue de cet axe, tu sauras :
- Comprendre l'organisation projet/apps et le settings.py
- Définir des modèles avec relations et migrations
- Utiliser l'admin Django pour générer une interface CRUD gratuite
- Construire une API REST avec Django REST Framework (DRF)
- Authentifier avec sessions ou JWT (SimpleJWT)
- Tester avec pytest-django
Pourquoi Django ?
Section intitulée « Pourquoi Django ? »| Pour | Contre |
|---|---|
| Tout fourni : ORM, migrations, admin auto, auth, templates, sessions, formulaires | Verbeux, beaucoup de magie implicite |
| Admin auto = interface CRUD complète gratuite pour gérer les données | Convention « project + apps » à digérer |
| Mature depuis 2005, écosystème riche | Async ajouté tardivement (mature en 6.0+) |
| Excellent pour un CRUD complet d’app métier | Sur-dimensionné pour un microservice |
Verdict 2026 : Django reste l’arme absolue pour des apps métier complètes où l’admin et la productivité priment. Pour une API moderne async, FastAPI est plus adapté.
Django 6.0 — nouveautés clés
Section intitulée « Django 6.0 — nouveautés clés »Django 6.0 (sortie fin 2025, LTS) apporte :
- Async views matures (depuis 4.1, stabilisées en 5.x, optimisées en 6.0).
- Async ORM amélioré :
await Model.objects.aget(...),async for obj in qs. - Améliorations de performances sur le templating et le routage.
- Drop du support Python 3.10 ; cible Python 3.12+.
Installation rapide
Section intitulée « Installation rapide »# Avec uv (recommandé en 2026)uv init taskly-djangocd taskly-djangouv add django djangorestframework
# Créer un projetuv run django-admin startproject config .
# Lanceruv run python manage.py migrateuv run python manage.py runserver# http://127.0.0.1:8000Structure d’un projet Django
Section intitulée « Structure d’un projet Django »taskly-django/├── manage.py ← CLI Django├── pyproject.toml├── config/ ← « project » : settings, urls racine, ASGI/WSGI│ ├── __init__.py│ ├── settings.py│ ├── urls.py│ └── asgi.py├── apps/ ← convention : un dossier "apps" qui contient les apps│ ├── accounts/ ← une « app » Django (module isolé)│ │ ├── models.py│ │ ├── views.py│ │ ├── urls.py│ │ ├── serializers.py ← DRF│ │ ├── admin.py│ │ └── migrations/│ └── tasks/└── tests/Concept clé : un projet Django contient plusieurs apps. Une app est une unité réutilisable (modèles + vues + URLs + templates). Tu peux avoir 1 app pour accounts, 1 pour tasks, 1 pour billing.
Models — l’ORM Django
Section intitulée « Models — l’ORM Django »from django.db import modelsfrom django.contrib.auth import get_user_model
User = get_user_model()
class Task(models.Model): owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='tasks') title = models.CharField(max_length=200) description = models.TextField(blank=True) done = models.BooleanField(default=False) due_at = models.DateTimeField(null=True, blank=True) created_at = models.DateTimeField(auto_now_add=True)
class Meta: ordering = ['-created_at'] indexes = [ models.Index(fields=['owner', '-created_at']), ]
def __str__(self) -> str: return self.titleMigrations
Section intitulée « Migrations »uv run python manage.py makemigrationsuv run python manage.py migrateDjango génère automatiquement les migrations SQL à partir de tes modifs models.py. Le système est mature et gère bien les diffs.
Querysets
Section intitulée « Querysets »# Filtrertasks = Task.objects.filter(owner=user, done=False)
# Joindre (évite N+1)tasks = Task.objects.select_related('owner').filter(done=False)
# Many-to-many / reverse FKtasks = Task.objects.prefetch_related('comments').all()
# Agrégerfrom django.db.models import Countstats = Task.objects.aggregate(total=Count('id'))
# Async (Django 4.1+)tasks = await Task.objects.filter(owner=user).acount()async for task in Task.objects.filter(owner=user): print(task.title)Admin Django — la killer feature
Section intitulée « Admin Django — la killer feature »from django.contrib import adminfrom .models import Task
@admin.register(Task)class TaskAdmin(admin.ModelAdmin): list_display = ('title', 'owner', 'done', 'created_at') list_filter = ('done', 'owner') search_fields = ('title', 'description') readonly_fields = ('created_at',)Tu obtiens gratuitement une interface complète à /admin/ :
- Liste filtrable, recherchable, paginée.
- Formulaires de création/édition générés depuis les modèles.
- Permissions par utilisateur/groupe.
- Historique des modifications.
C’est ce qui rend Django imbattable quand tu as besoin d’un back-office sans coder.
Django REST Framework (DRF) — pour les APIs
Section intitulée « Django REST Framework (DRF) — pour les APIs »DRF est l’extension de référence pour exposer une API JSON. Bien que NestJS-niveau de productivité.
uv add djangorestframework djangorestframework-simplejwtSerializers
Section intitulée « Serializers »from rest_framework import serializersfrom .models import Task
class TaskSerializer(serializers.ModelSerializer): class Meta: model = Task fields = ['id', 'title', 'description', 'done', 'due_at', 'created_at'] read_only_fields = ['id', 'created_at']ViewSets + Routers
Section intitulée « ViewSets + Routers »from rest_framework import viewsets, permissionsfrom .models import Taskfrom .serializers import TaskSerializer
class TaskViewSet(viewsets.ModelViewSet): serializer_class = TaskSerializer permission_classes = [permissions.IsAuthenticated]
def get_queryset(self): return Task.objects.filter(owner=self.request.user)
def perform_create(self, serializer): serializer.save(owner=self.request.user)from rest_framework.routers import DefaultRouterfrom .views import TaskViewSet
router = DefaultRouter()router.register(r'tasks', TaskViewSet, basename='task')urlpatterns = router.urls→ 5 routes générées automatiquement : GET /tasks/, POST /tasks/, GET /tasks/:id/, PATCH /tasks/:id/, DELETE /tasks/:id/.
Auth JWT avec SimpleJWT
Section intitulée « Auth JWT avec SimpleJWT »REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework_simplejwt.authentication.JWTAuthentication', ),}
# config/urls.pyfrom rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
urlpatterns += [ path('api/auth/login/', TokenObtainPairView.as_view()), path('api/auth/refresh/', TokenRefreshView.as_view()),]Tu obtiens /api/auth/login/ qui prend { username, password } et renvoie { access, refresh } — JWT prêts à l’emploi.
Tests avec pytest-django
Section intitulée « Tests avec pytest-django »uv add --dev pytest pytest-djangoimport pytestfrom django.contrib.auth import get_user_modelfrom rest_framework.test import APIClient
User = get_user_model()
@pytest.fixturedef client(): return APIClient()
@pytest.fixturedef user(db): return User.objects.create_user(username='alice', password='password123')
def test_list_tasks_requires_auth(client): response = client.get('/api/tasks/') assert response.status_code == 401
def test_create_task(client, user): client.force_authenticate(user=user) response = client.post('/api/tasks/', {'title': 'Test'}) assert response.status_code == 201 assert response.data['title'] == 'Test'Déploiement
Section intitulée « Déploiement »| Composant | Recommandation |
|---|---|
| Serveur WSGI | Gunicorn (sync) ou Uvicorn (async via Daphne) |
| Reverse proxy | Nginx ou Caddy |
| Static files | Whitenoise pour les servir directement (simple) |
| DB | PostgreSQL (le default Django) |
| Cache | Redis |
| Plateforme | Fly.io, Render, Railway |
# Démarrage prod typiqueuv run gunicorn config.wsgi:application --workers 4 --bind 0.0.0.0:8000Auto-évaluation
Section intitulée « Auto-évaluation »Pour aller plus loin
Section intitulée « Pour aller plus loin »- Django Documentation — docs.djangoproject.com
- Two Scoops of Django — Daniel & Audrey Roy Greenfeld (livre culte des bonnes pratiques)
- Django REST Framework Docs — django-rest-framework.org
- djangopackages.org — annuaire des packages Django
- Awesome Django — github.com/wsvincent/awesome-django
Le projet taskly-api sera implémenté en FastAPI (notre référence). Pour faire la même chose en Django, tu peux suivre la doc DRF avec les modèles ci-dessus comme point de départ.