L’ORM de Django propose une API riche pour interroger la base sans écrire de SQL brut. Voici un panorama des outils les plus courants, illustrés par des exemples concrets.
13 méthodes indispensables
| Méthode | Retour | Description rapide |
|---|---|---|
all() |
QuerySet | Tous les enregistrements |
filter(**critères) |
QuerySet | Lignes correspondant aux critères |
get(**critères) |
Instance | Une et une seule ligne |
exclude(**critères) |
QuerySet | Lignes ne correspondant pas aux critères |
values(*champs) |
QuerySet de dict | Colonnes choisies sous forme de dictionnaires |
values_list(*champs) |
QuerySet de tuples | Colonnes choisies sous forme de tuples |
order_by(*champs) |
QuerySet | Tri |
reverse() |
QuerySet | Tri inversé |
distinct() |
QuerySet | Doublons supprimés |
count() |
int | Nombre de lignes |
first() |
Instance ou None | Premier élément |
last() |
Instance ou None | Dernier élément |
exists() |
bool | Présence d’au moins un résultat |
Différences entre objet unique et QuerySet
- Instance de modèle : accès direct aux attributs (
obj.nom), mais pas deupdate()ni devalues(). - QuerySet : ensemble d’instances, compatible
values(),update(), slicing, etc.
Filtres via les doubles underscores
# intervalle
Article.objects.filter(id__range=(10, 20))
# inclusion
Article.objects.filter(statut__in=['publié', 'archivé'])
# texte
Article.objects.filter(titre__icontains='django')
# dates
Article.objects.filter(pub_date__year=2023)
Relations : navigation par objets
One-To-Many (Livre → Éditeur)
# sens direct
livre.editeur.nom
# sens inverse
editeur.livre_set.all()
One-To-One (Auteur → Profil)
auteur.profil.bio
profil.auteur.nom
Many-To-Many (Livre ↔ Auteur)
livre.auteurs.all()
auteur.livres.all()
Jointures via doubles underscores
# éditeur du livre « Django avancé »
Livre.objects.filter(titre='Django avancé').values('editeur__nom')
# livres parus chez « Eyrolles »
Editeur.objects.filter(nom='Eyrolles').values('livre__titre')
Manipulateurs de relations Many-To-Many
livre = Livre.objects.get(pk=1)
livre.auteurs.add(auteur1, auteur2) # ou .set([id1, id2])
livre.auteurs.create(nom='Alice') # crée et rattache
livre.auteurs.remove(auteur3) # retire
livre.auteurs.clear() # vide
Optimisations
- Lazy loading : la requête SQL n’est émise qu’au premier usage.
- Cache : un QuerySet évalué est stocké en mémoire.
exists(): évite de charger toutes les lignes.iterator(): parcourt les résultats sans les mettre en cache (utile pour gros volumes).
Agrégats
from django.db.models import Avg, Count, Max
Livre.objects.aggregate(prix_moyen=Avg('prix'))
Editeur.objects.annotate(nb_livres=Count('livre'))
Regroupements
# salaire moyen par département
Employe.objects.values('departement__nom').annotate(
salaire_moyen=Avg('salaire')
)
F() et Q()
from django.db.models import F, Q
# comparaison de deux colonnes
Commande.objects.filter(quantite__gt=F('stock'))
# conditions complexes
Commande.objects.filter(
Q(client='Dupont') | Q(montant__gt=1000),
statut='payé'
)
Verrous et SQL brut
# verrouillage en lecture/écriture
Commande.objects.select_for_update().filter(client=u)
# requête SQL personnalisée
Personne.objects.raw(
'SELECT * FROM personne WHERE age > %s',
[18]
)