Référence de l’API QuerySet

Ce document détaille l’API des objets QuerySet. Il augmente les contenus présentés dans les guides des modèles et des requêtes de base de données, il est donc conseillé de lire et de comprendre ces derniers avant de lire celui-ci.

Tout au long de cette référence, nous utiliserons les modèles d’exemple Weblog présentés dans le guide des requêtes de base de données.

Quand les objets QuerySet sont évalués

En interne, un objet QuerySet peut être construit, filtré, segmenté ou transmis sans devoir accéder à la base de données. Aucune activité de base de données n’est effectivement créée tant qu’une action ne provoque pas l’évaluation du jeu de requête.

Un QuerySet est évalué dans les contextes suivants :

  • Itération. Un QuerySet est itérable, et il exécute sa requête de base de données lors de la première itération. Par exemple, ceci affiche le titre de tous les articles de la base de données :

    for e in Entry.objects.all():
        print(e.headline)
    

    Note : ne faites pas cela si vous voulez uniquement savoir s’il existe au moins un résultat. Il est plus efficace d’utiliser exists().

  • Segmentation. Comme expliqué dans Limitation des QuerySet, un QuerySet peut être segmenté par la syntaxe de segmentation de liste de Python. La segmentation d’un QuerySet non évalué renvoie habituellement un autre objet QuerySet non évalué, mais Django exécute la requête de base de données si vous employez le paramètre step de la syntaxe de segmentation, et dans ce cas, une liste est renvoyée. La segmentation d’un QuerySet qui a été évalué renvoie également une liste.

    Notez également que bien que la segmentation d’un objet QuerySet non évalué renvoie un autre QuerySet non évalué, sa modification ultérieure (par ex. par l’ajout de filtres ou en modifiant l’ordre de tri) n’est plus permise, car cela se traduirait difficilement en termes SQL et la signification d’une telle opération ne serait pas claire non plus.

  • « Pickling »/mise en cache. Consultez la section suivante pour plus de détails sur les implications du « pickling » des objets QuerySets. L’élément important dans la perspective de cette section est que les résultats sont lus à partir de la base de données.

  • repr(). Un QuerySet est évalué lorsqu’on l’inclut dans un appel repr(). Ceci pour des raisons pratiques dans l’interpréteur interactif Python, afin de pouvoir visualiser immédiatement les résultats en utilisant l’API de manière interactive.

  • len(). Un QuerySet est évalué lorsqu’on l’inclut dans un appel len(). Ceci renvoie comme prévu la longueur de la liste résultante.

    Note : si vous avez seulement besoin de connaître le nombre d’enregistrements du résultat (et que vous n’avez pas besoin des objets eux-mêmes), il est bien plus efficace de gérer la comptabilisation au niveau de la base de données en utilisant le code SQL SELECT COUNT(*). Django fournit une méthode count() précisément pour cette raison.

  • list(). Force l’évaluation d’un QuerySet lorsqu’on l’inclut dans un appel list(). Par exemple :

    entry_list = list(Entry.objects.all())
    
  • bool(). Le test d’un QuerySet dans un contexte booléen, comme par exemple en employant bool(), or, and ou if, va provoquer l’exécution de la requête. S’il existe au moins un résultat, le QuerySet renverra True, sinon False. Par exemple :

    if Entry.objects.filter(headline="Test"):
       print("There is at least one Entry with the headline Test")
    

    Note : si tout ce qui vous intéresse est de déterminer s’il existe au moins un résultat (et que vous n’avez pas besoin des objets eux-mêmes), il est plus efficace d’utiliser exists().

QuerySet et « pickling »

Si vous transformez un QuerySet par pickle, cela force tous les résultats à être chargés en mémoire avant le processus de pickling. Cette opération précède généralement une mise en cache, et lorsque le jeu de requête est récupéré du cache, il est souhaitable que les résultats soient disponibles et prêts à être utilisés (une lecture depuis la base de données peut prendre du temps, ce qui annulerait l’avantage du cache). Cela signifie que lorsqu’un objet QuerySet est reconstruit depuis sa représentation « pickle », il contient les résultats du moment où il a été transformé par « pickle », et non pas les résultats du moment actuel en base de données.

Si vous ne vouliez que mettre en « pickle » les informations utiles pour recréer le QuerySet à partir de la base de données au moment voulu, fournissez à pickle l’attribut query de QuerySet. Vous pouvez ensuite recréer le QuerySet original (sans chargement des résultats) en écrivant du code semblable à ceci :

>>> import pickle
>>> query = pickle.loads(s)     # Assuming 's' is the pickled string.
>>> qs = MyModel.objects.all()
>>> qs.query = query            # Restore the original 'query'.

L’attribut query est un objet opaque. Il constitue la représentation interne de la construction de la requête et ne fait pas partie de l’API publique. Cependant, la sérialisation et la désérialisation « pickle » du contenu de cet attribut est une opération sûre (et totalement acceptable).

Il n’est pas possible de partager des sérialisations « pickle » entre différentes versions

Des sérialisations « pickle » de QuerySets ne sont valables que pour la version de Django utilisée pour les générer. Si vous produisez du contenu « pickle » avec une version N de Django, il n’y a aucune garantie que ce contenu soit lisible par une version N+1 de Django. La sérialisation « pickle » ne doit pas être utilisée dans le cadre d’une stratégie d’archivage à long terme.

Comme des erreurs de compatibilité de pickle peuvent être difficiles à diagnostiquer, comme par exemple des objets silencieusement corrompus, un avertissement RuntimeWarning est produit si vous essayez de désérialiser un jeu de requête dans une version de Django différente de celle qui a été utilisée pour la sérialisation.

API QuerySet

Voici la déclaration formelle d’un QuerySet:

class QuerySet(model=None, query=None, using=None)[source]

Normalement, lorsqu’on manipule un QuerySet, on le fait en enchaînant des filtres. Pour accomplir cela, la plupart des méthodes de QuerySet renvoient de nouveaux objets QuerySet. Ces méthodes sont décrites en détails plus loin dans cette section.

La classe QuerySet possède deux attributs publics qu’il est possible d’utiliser pour introspection :

ordered

True si le QuerySet est trié, c’est-à-dire qu’il comporte une clause order_by() ou un tri par défaut au niveau du modèle. Sinon, la valeur est False.

db

La base de données utilisée si la requête est exécutée tout de suite.

Note

Le paramètre query de QuerySet existe pour que des sous-classes spécialisées telles que GeoQuerySet puissent reconstruire l’état interne des requêtes. La valeur du paramètre est une représentation opaque de l’état de la requête et ne fait pas partie de l’API publique. Pour faire simple : si vous vous demandez ce que c’est, c’est que vous n’en avez pas besoin.

Méthodes renvoyant de nouveaux QuerySet

Django fournit un grand nombre de méthodes d’affinage des QuerySet qui modifient soit le type de résultats renvoyés par le QuerySet ou sa façon d’exécuter la requête SQL.

filter()

filter(**kwargs)

Renvoie un nouveau QuerySet contenant les objets qui répondent aux paramètres de recherche donnés.

Les paramètres de recherche (**kwargs) doivent être dans le format décrit dans Recherches dans les champs ci-dessous. Plusieurs paramètres sont combinés via AND dans l’instruction SQL sous-jacente.

Si vous avez besoin d’exécuter des requêtes plus complexes (par exemple des requêtes contenant des instruction avec OR (OU)), vous pouvez utiliser des objets Q.

exclude()

exclude(**kwargs)

Renvoie un nouveau QuerySet contenant les objets qui ne répondent pas aux paramètres de recherche donnés.

Les paramètres de recherche (**kwargs) doivent être dans le format décrit dans Recherches dans les champs ci-dessous. Plusieurs paramètres sont combinés via AND dans l’instruction SQL sous-jacente, et le tout est englobé dans un NOT().

Cet exemple exclut tous les éléments dont pub_date est postérieure à 2005-1-3 ET dont headline contient « Hello » :

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3), headline='Hello')

En termes SQL, cela donne :

SELECT ...
WHERE NOT (pub_date > '2005-1-3' AND headline = 'Hello')

Cet exemple exclut tous les éléments dont pub_date est postérieure à 2005-1-3 OU dont headline contient « Hello »

Entry.objects.exclude(pub_date__gt=datetime.date(2005, 1, 3)).exclude(headline='Hello')

En termes SQL, cela donne :

SELECT ...
WHERE NOT pub_date > '2005-1-3'
AND NOT headline = 'Hello'

Notez que le second exemple est plus restrictif.

Si vous avez besoin d’exécuter des requêtes plus complexes (par exemple des requêtes contenant des instruction avec OR (OU)), vous pouvez utiliser des objets Q.

annotate()

annotate(*args, **kwargs)

Annote chaque objet du QuerySet avec la liste fournie d’expressions de requêtes. Une expression peut être une valeur simple, une référence à un champ du modèle (ou de tout modèle lié) ou une expression d’agrégation (moyennes, sommes, etc.) qui a été calculée sur les objets en liaison avec les objets du QuerySet.

Chaque paramètre d’annotate() est une annotation qui sera ajoutée à chaque objet du QuerySet renvoyé.

Les fonctions d’agrégation fournies par Django sont décrites plus loin dans Fonctions d’agrégation.

Les annotations spécifiées par des paramètres nommés utilisent la clé comme alias d’annotation. Les paramètres anonymes seront dotés d’un alias généré automatiquement sur la base du nom de la fonction d’agrégation et du champ de modèle sur lequel porte l’agrégation. Seules les expressions d’agrégation qui font référence à un seul champ peuvent constituer des paramètres anonymes. Tout le reste doit se présenter sous la forme d’un paramètre nommé.

Par exemple, si vous avez affaire à une liste de blogs, il peut être intéressant de déterminer le nombre d’articles écrits dans chaque blog :

>>> from django.db.models import Count
>>> q = Blog.objects.annotate(Count('entry'))
# The name of the first blog
>>> q[0].name
'Blogasaurus'
# The number of entries on the first blog
>>> q[0].entry__count
42

Le modèle Blog ne définit pas d’attribut entry__count par lui-même, mais en utilisant un paramètre nommé pour définir la fonction d’agrégation, vous pouvez contrôler le nom de l’annotation :

>>> q = Blog.objects.annotate(number_of_entries=Count('entry'))
# The number of entries on the first blog, using the name provided
>>> q[0].number_of_entries
42

Pour une présentation approfondie de l’agrégation, consultez le guide thématique sur l’agrégation.

order_by()

order_by(*fields)

Par défaut, les résultats renvoyés par un QuerySet sont triés selon le tuple de tri défini par l’option ordering de la classe Meta du modèle. Vous pouvez surcharger cela pour chaque QuerySet en utilisant la méthode order_by.

Exemple :

Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

Les résultats ci-dessus seront triés par pub_date dans l’ordre chronologique inverse, puis par headline dans l’ordre alphabétique. Le signe moins devant "-pub_date" indique l’inversion de l’ordre de tri. Pour trier de manière aléatoire, utilisez "?" comme ceci :

Entry.objects.order_by('?')

Note : les requêtes order_by('?') peuvent être coûteuses et lentes, en fonction du moteur de base de données utilisé.

Pour trier selon un champ d’un autre modèle, utilisez la même syntaxe que lorsque vous interrogez la base de données en traversant des relations. C’est-à-dire, le nom du champ suivi d’un double soulignement (__), suivi du nom du champ du nouveau modèle, et ainsi de suite pour autant de modèles que vous souhaitez combiner. Par exemple :

Entry.objects.order_by('blog__name', 'headline')

Si vous essayez de trier selon un champ qui constitue une relation vers un autre modèle, Django utilise le tri par défaut du modèle lié, ou trie selon la clé primaire du modèle lié si aucun attribut Meta.ordering n’est présent. Par exemple, comme le modèle Blog ne possède par d’ordre de tri par défaut :

Entry.objects.order_by('blog')

… est identique à :

Entry.objects.order_by('blog__id')

Si Blog comportait ordering = ['name'], alors le premier jeu de requête serait identique à :

Entry.objects.order_by('blog__name')

Il est également possible de trier un jeu de requête selon un champ lié, sans provoquer de JOIN supplémentaire, en se référant au nom _id du champ lié :

# No Join
Entry.objects.order_by('blog_id')

# Join
Entry.objects.order_by('blog__id')

Il est aussi possible de trier par des expressions de requête en appelant asc() ou desc() sur l’expression :

Entry.objects.order_by(Coalesce('summary', 'headline').desc())

Soyez prudent lorsque vous triez selon des champs de modèles liés et que vous utilisez également distinct(). Consultez la note dans distinct() pour une explication sur l’impact possible du tri selon des modèles liés sur les résultats attendus.

Note

Il est autorisé de définir un champ multivalué comme critère de tri (par exemple, un champ ManyToManyField ou la relation inverse d’un champ ForeignKey).

Considérez ce cas :

class Event(Model):
   parent = models.ForeignKey(
       'self',
       on_delete=models.CASCADE,
       related_name='children',
   )
   date = models.DateField()

Event.objects.order_by('children__date')

Dans ce cas, il est possible que plusieurs données de tri existent pour chaque Event. Un Event avec plusieurs children sera renvoyé plusieurs fois dans le nouveau QuerySet créé par order_by(). En d’autres termes, l’application de order_by() sur le QuerySet peut renvoyer plus d’éléments que l’ensemble de départ, ce qui n’est ni le résultat attendu, ni utile.

Ainsi, il faut être très prudent lorsqu’on utilise un champ multivalué pour trier des résultats. Si vous pouvez être certain qu’il n’y aura qu’une donnée de tri pour chaque élément que vous triez, cette approche ne devrait pas poser de problème. Dans le cas contraire, vérifiez soigneusement que les résultats correspondent à votre attente.

Il n’est pas possible d’indiquer si le tri doit être sensible à la casse ou non. Dans cette optique, Django trie les résultats en fonction du comportement habituel de tri du moteur de base de données.

Vous pouvez trier selon un champ converti en minuscules avec Lower, ce qui aboutira à un tri insensible à la casse :

Entry.objects.order_by(Lower('headline').desc())

Si vous ne voulez pas qu’une requête soit triée, même pas selon le tri par défaut, appelez order_by() sans paramètre.

Vous pouvez savoir si une requête est triée ou pas en interrogeant l’attribut QuerySet.ordered, qui vaut True lorsque le QuerySet a été trié d’une manière ou d’une autre.

Chaque appel à order_by() efface tout ordre de tri préexistant. Par exemple, cette requête sera triée par pub_date et non pas par headline:

Entry.objects.order_by('headline').order_by('pub_date')

Avertissement

Le tri n’est pas une opération anodine. Chaque champ ajouté dans les critères de tri implique un coût au niveau de la base de données. Chaque clé étrangère ajoutée inclut aussi implicitement tous ses champs de tri par défaut.

Si une requête ne possède pas d’ordre de tri, les résultats sont renvoyés de la base de données dans un ordre non défini. Un ordre particulier ne peut être garanti que si l’ordre se base sur un ou des champs qui identifient chaque objet du résultat de manière unique. Par exemple, si un champ nom n’est pas unique, le tri par ce champ ne garantit pas que les objets de même nom apparaissent toujours dans le même ordre.

reverse()

reverse()

Utilisez la méthode reverse() pour inverser l’ordre dans lequel les éléments d’un jeu de requête sont renvoyés. En appelant reverse() une seconde fois, l’ordre est rétabli selon l’ordre initial normal.

Pour récupérer les cinq « derniers » éléments d’un jeu de requête, vous pourriez écrire cela :

my_queryset.reverse()[:5]

Notez que ce n’est pas tout à fait la même chose que de segmenter à partir de la fin d’une liste en Python. L’exemple ci-dessus renvoie en premier le dernier élément, puis l’avant-dernier et ainsi de suite. Si nous avions une liste Python et que nous avions appliqué list[-5:], nous aurions obtenu les 5 derniers éléments. Django ne prend pas en charge ce mode d’accès avec les jeux de requête (segmentation à partir de la fin), car il n’est pas possible de le faire efficacement en SQL.

Signalons également que reverse() ne devrait généralement être appelé que pour un QuerySet dont l’ordre de tri est défini (par exemple, lors d’une requête sur un modèle définissant un tri par défaut ou en appelant order_by()). Si un QuerySet donné ne comporte pas d’ordre de tri, l’appel reverse() sur cet objet n’a pas d’effet réel (le tri n’étant pas défini avant l’appel à reverse(), il ne le sera pas plus après).

distinct()

distinct(*fields)

Renvoie un nouveau QuerySet utilisant SELECT DISTINCT dans sa requête SQL. Les lignes dupliquées sont alors supprimées des résultats de la requête.

Par défaut, un QuerySet n’élimine pas les lignes dupliquées. En pratique, c’est rarement un problème, car les requêtes simples comme Blog.objects.all() n’introduisent pas la possibilité de lignes de résultats dupliquées. Cependant, si la requête s’étend sur plusieurs tables, il est possible d’obtenir des résultats dupliqués lors de l’évaluation du QuerySet. C’est alors que distinct() devient utile.

Note

Tout champ mentionné dans un appel order_by() est inclus dans les colonnes SELECT de l’instruction SQL. Cela peut parfois amener à des résultats inattendus lors d’une utilisation conjointe avec distinct(). Si vous triez en fonction de champs d’un modèle lié, ces champs seront ajoutés aux colonnes sélectionnées et certaines lignes qui seraient normalement dupliquées (donc supprimées) apparaissent alors comme distinctes. Comme ces colonnes supplémentaires n’apparaissent pas dans les résultats renvoyés (elles ne servent qu’au tri), il peut sembler que des lignes dupliquées, non distinctes sont renvoyées malgré tout.

De même, si vous utilisez une requête values() pour limiter les colonnes sélectionnées, toute colonne mentionnée dans order_by() (ou dans un tri par défaut d’un modèle) fera tout de même partie de la requête et pourrait interférer avec l’unicité des résultats.

La morale à retenir est que si vous utilisez distinct(), vous devez rester prudent lors des tris selon des modèles liés. De même, lorsque vous combinez l’utilisation de distinct() et de values(), soyez prudent avec les champs de tri qui ne figurent pas dans l’appel à values().

Avec PostgreSQL uniquement, vous pouvez transmettre des paramètres positionnels (*fields) afin de préciser les noms des champs sur lesquels l’instruction DISTINCT s’applique. Cela produit une requête SQL du genre SELECT DISTINCT ON. Voici la différence. Pour un appel distinct() normal, la base de données compare chaque champ de chaque ligne pour déterminer quelles lignes sont distinctes. Lors d’un appel distinct() qui spécifie des noms de champs, la base de données ne compare que les champs indiqués pour déterminer les lignes distinctes.

Note

Lorsque vous indiquez des noms de champs, vous devez fournir une clause order_by() pour le QuerySet, et les champs dans order_by() doivent commencer par les champs de distinct(), dans le même ordre.

Par exemple, SELECT DISTINCT ON (a) renvoie la première ligne pour chaque valeur différente dans la colonne a. Si vous n’indiquez pas de tri, le choix de la ligne renvoyée est arbitraire.

Exemples (à partir du deuxième exemple, cela ne fonctionne qu’avec PostgreSQL) :

>>> Author.objects.distinct()
[...]

>>> Entry.objects.order_by('pub_date').distinct('pub_date')
[...]

>>> Entry.objects.order_by('blog').distinct('blog')
[...]

>>> Entry.objects.order_by('author', 'pub_date').distinct('author', 'pub_date')
[...]

>>> Entry.objects.order_by('blog__name', 'mod_date').distinct('blog__name', 'mod_date')
[...]

>>> Entry.objects.order_by('author', 'pub_date').distinct('author')
[...]

Note

Gardez en tête que order_by() utilise les éventuels ordres de tri par défaut définis pour les modèles liés. Il peut être nécessaire de trier explicitement selon le nom _id de la relation ou selon le champ référencé pour s’assurer que les expressions DISTINCT ON correspondent à celles du début de la clause ORDER BY. Par exemple, si le modèle Blog définit un tri ordering selon son champ name:

Entry.objects.order_by('blog').distinct('blog')

…ne fonctionnera pas car la requête serait triée par blog__name et ne correspondra donc pas à l’expression DISTINCT ON. Il faudrait trier explicitement selon le champ _id de la relation (blog_id dans ce cas) ou selon le champ référencé (blog__pk) pour être certain que les deux expressions correspondent.

values()

values(*fields)

Renvoie un QuerySet qui renvoie des dictionnaires lorsqu’on l’utilise de manière itérable, au lieu d’instances de modèles.

Chacun de ces dictionnaires représente un objet, les clés correspondant aux noms d’attributs des objets de modèle.

Cet exemple compare les dictionnaires de values() avec des objets de modèle normaux :

# This list contains a Blog object.
>>> Blog.objects.filter(name__startswith='Beatles')
<QuerySet [<Blog: Beatles Blog>]>

# This list contains a dictionary.
>>> Blog.objects.filter(name__startswith='Beatles').values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>

La méthode values() accepte des paramètres positionnels facultatifs, *fields, qui définissent les noms de champs auxquels l’instruction SELECT se limitera. Si vous renseignez ces paramètres, chaque dictionnaire du résultat ne contiendra que les clés/valeurs des champs qui ont été indiqués. Si aucun de ces paramètres n’est présent, chaque dictionnaire du résultat contiendra une clé et une valeur pour tous les champs de la table de base de données correspondante.

Exemple :

>>> Blog.objects.values()
<QuerySet [{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}]>
>>> Blog.objects.values('id', 'name')
<QuerySet [{'id': 1, 'name': 'Beatles Blog'}]>

Quelques subtilités qui valent la peine d’être mentionnées :

  • Si un champ appelé foo est un champ ForeignKey, l’appel values() par défaut renvoie une clé de dictionnaire nommée foo_id, car il s’agit du nom interne de l’attribut de modèle stockant la valeur réelle (l’attribut foo se référant au modèle lié). Lorsque vous appelez values() et que vous indiquez des noms de champs, vous pouvez mentionner foo ou foo_id et vous obtiendrez le même résultat (la clé de dictionnaire correspond au nom du champ que vous avez mentionné).

    Par exemple :

    >>> Entry.objects.values()
    <QuerySet [{'blog_id': 1, 'headline': 'First Entry', ...}, ...]>
    
    >>> Entry.objects.values('blog')
    <QuerySet [{'blog': 1}, ...]>
    
    >>> Entry.objects.values('blog_id')
    <QuerySet [{'blog_id': 1}, ...]>
    
  • Lors d’une utilisation combinée de values() et de distinct(), soyez conscient que le tri peut affecter les résultats. Consultez la note dans distinct() pour plus de détails.

  • Si vous utilisez une clause values() après un appel à extra(), tout champ mentionné dans un paramètre select de extra() doit être explicitement inclus dans l’appel à values(). Lors de tout appel à extra() après un appel à values(), les champs sélectionnés supplémentaires sont ignorés.

  • Les appels à only() et defer() après values() n’ont pas de sens, et si vous le faites, vous obtiendrez une exception NotImplementedError.

C’est utile lorsque vous savez que vous n’aurez besoin que d’un petit nombre des champs disponibles et que vous n’aurez pas besoin des fonctionnalités d’un objet d’instance de modèle. Il est plus efficace de ne sélectionner que les champs dont vous aurez besoin.

Enfin, notez que vous pouvez appeler filter(), order_by(), etc. après l’appel à values(), ce qui signifie que ces deux appels sont identiques :

Blog.objects.values().order_by('id')
Blog.objects.order_by('id').values()

Les concepteurs de Django préfèrent placer en premier les méthodes affectant le code SQL, suivies (facultativement) par toute méthode affectant le format (comme values()), mais ce n’est pas essentiel. C’est l’occasion de mettre en évidence votre individualisme.

Vous pouvez aussi faire référence à des modèles liés par des relations inverses au travers d’attributs OneToOneField, ForeignKey et ManyToManyField:

>>> Blog.objects.values('name', 'entry__headline')
<QuerySet [{'name': 'My blog', 'entry__headline': 'An entry'},
     {'name': 'My blog', 'entry__headline': 'Another entry'}, ...]>

Avertissement

Comme les attributs ManyToManyField et les relations inverses peuvent posséder plusieurs lignes liées, leur inclusion peut produire un effet multiplicateur sur la taille du jeu de résultats. Et plus il y a de tels champs dans la requête values(), plus l’effet est prononcé, car toutes les combinaisons possibles sont effectuées et renvoyées.

values_list()

values_list(*fields, flat=False)

Semblable à values(), sauf qu’au lieu de renvoyer des dictionnaires, ce sont des tuples qui sont renvoyés lors de l’itération des résultats. Chaque tuple contient les valeurs des champs dans la position respective de leur apparition dans l’appel à values_list() — premier champ comme premier élément, etc. Par exemple :

>>> Entry.objects.values_list('id', 'headline')
[(1, 'First entry'), ...]

Si vous n’indiquez qu’un seul champ, il est aussi possible d’indiquer le paramètre flat. S’il vaut True, cela signifie que les résultats renvoyés sont des valeurs uniques au lieu de tuples simples. Cet exemple devrait éclairer la différence :

>>> Entry.objects.values_list('id').order_by('id')
[(1,), (2,), (3,), ...]

>>> Entry.objects.values_list('id', flat=True).order_by('id')
[1, 2, 3, ...]

C’est une erreur d’indiquer le paramètre flat lorsqu’il y a plus d’un champ.

Si vous n’indiquez aucune valeur dans values_list(), tous les champs du modèle sont pris en compte dans le résultat, dans leur ordre de déclaration.

Un besoin fréquent est d’obtenir une valeur de champ spécifique d’une certaine instance de modèle. Pour faire cela, utilisez values_list() suivie d’un appel à get():

>>> Entry.objects.values_list('headline', flat=True).get(pk=1)
'First entry'

values() et values_list() doivent toutes deux être considérées comme des optimisations pour un cas d’utilisation spécifique : récupérer un sous-ensemble de données sans la surcharge de création des instances de modèles. Cette métaphore ne vaut plus lorsqu’on a affaire à des relations plusieurs-à-plusieurs ou multivaluées d’une autre manière. (comme la relation un-à-plusieurs d’une clé étrangère inverse) car la supposition « une ligne, un objet » ne tient plus.

Par exemple, remarquez le comportement lorsqu’une requête traverse un champ ManyToManyField:

>>> Author.objects.values_list('name', 'entry__headline')
[('Noam Chomsky', 'Impressions of Gaza'),
 ('George Orwell', 'Why Socialists Do Not Believe in Fun'),
 ('George Orwell', 'In Defence of English Cooking'),
 ('Don Quixote', None)]

Les auteurs avec plusieurs Entry apparaissent plusieurs fois et les auteurs sans Entry possèdent None comme valeur de ce champ.

De la même façon, lors d’une requête par clé étrangère inverse, None apparaît pour les entrées sans auteur :

>>> Entry.objects.values_list('authors')
[('Noam Chomsky',), ('George Orwell',), (None,)]

dates()

dates(field, kind, order='ASC')

Renvoie un QuerySet dont l’évaluation produit une liste d’objets datetime.date représentant toutes les dates disponibles d’un type particulier dans le contenu QuerySet.

field doit être le nom d’un champ DateField du modèle. kind doit être soit "year", "month" ou "day". Chaque objet datetime.date de la liste de résultats est « tronqué » selon le type donné.

  • "year" renvoie une liste de toutes les valeurs d’années distinctes pour le champ.

  • "month" renvoie une liste de toutes les valeurs d’années/mois distinctes pour le champ.

  • "day" renvoie une liste de toutes les valeurs d’années/mois/jours distinctes pour le champ.

order, dont la valeur par défaut est 'ASC', doit contenir soit 'ASC' (chronologique), soit 'DESC' (chronologique inverse). Cela indique comment trier les résultats.

Exemples :

>>> Entry.objects.dates('pub_date', 'year')
[datetime.date(2005, 1, 1)]
>>> Entry.objects.dates('pub_date', 'month')
[datetime.date(2005, 2, 1), datetime.date(2005, 3, 1)]
>>> Entry.objects.dates('pub_date', 'day')
[datetime.date(2005, 2, 20), datetime.date(2005, 3, 20)]
>>> Entry.objects.dates('pub_date', 'day', order='DESC')
[datetime.date(2005, 3, 20), datetime.date(2005, 2, 20)]
>>> Entry.objects.filter(headline__contains='Lennon').dates('pub_date', 'day')
[datetime.date(2005, 3, 20)]

datetimes()

datetimes(field_name, kind, order='ASC', tzinfo=None)

Renvoie un QuerySet dont l’évaluation produit une liste d’objets datetime.datetime représentant toutes les dates disponibles d’un type particulier dans le contenu QuerySet.

field_name doit correspondre au nom d’un champ ``DateTimeField``de votre modèle.

kind doit être soit "year", "month", "day", "hour", "minute" ou "second". Chaque objet datetime.datetime de la liste de résultats est « tronqué » selon le type donné.

order, dont la valeur par défaut est 'ASC', doit contenir soit 'ASC' (chronologique), soit 'DESC' (chronologique inverse). Cela indique comment trier les résultats.

tzinfo définit le fuseau horaire dans lequel les dates/heures sont converties avant leur troncature. En effet, un date/heure peut être représentée différemment en fonction du fuseau horaire actif. Ce paramètre doit être un objet datetime.tzinfo. S’il vaut None, Django utilise le fuseau horaire actuel. Il n’a aucun effet lorsque USE_TZ vaut False.

Note

Cette fonction effectue la conversion de fuseau horaire directement dans la base de données. En conséquence, la base de données doit être capable d’interpréter la valeur de tzinfo.tzname(None). Cela se traduit dans les exigences suivantes :

none()

none()

L’appel à none() crée un jeu de requête qui ne renvoie jamais aucun objet et qui ne génère pas de requête lorsqu’on accède à ses résultats. Un jeu de requête qs.none() est une instance de EmptyQuerySet.

Exemples :

>>> Entry.objects.none()
<QuerySet []>
>>> from django.db.models.query import EmptyQuerySet
>>> isinstance(Entry.objects.none(), EmptyQuerySet)
True

all()

all()

Renvoie une copie du QuerySet actuel (ou d’une sous-classe QuerySet). Cela peut être utile dans les situations où il peut être possible de recevoir soit un gestionnaire de modèle, soit un QuerySet, et que les résultats doivent passer encore par d’autres filtres. Après avoir appelé all() sur l’un des types d’objet, vous obtenez dans tous les cas un QuerySet en retour.

Lorsqu’un résultat QuerySet est évalué, il met normalement ses résultats en cache. Si les données dans la base de données peuvent avoir été modifiées depuis l’évaluation d’un QuerySet, vous pouvez obtenir des résultats mis à jour de la même requête en appelant all() sur un QuerySet déjà évalué.

extra()

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

Il peut arriver parfois que la syntaxe de requête de Django ne puisse pas exprimer facilement une clause WHERE complexe. Pour ces cas extrêmes, Django fournit le modificateur de QuerySet extra(), un point d’entrée pour injecter des clauses spécifiques dans le code SQL généré par un QuerySet.

N’utilisez cette méthode qu’en dernier recours

Il s’agit d’une ancienne API que nous prévoyons de rendre obsolète à un moment donné. Ne l’utilisez que si vous ne pouvez pas exprimer votre requête en employant d’autres méthodes de jeux de requêtes. Si vous êtes contraint de l’utiliser, créez un ticket en indiquant le mot-clé QuerySet.extra et en présentant votre cas d’utilisation (sans oublier de vérifier d’abord d’éventuels tickets existants) afin que nous puissions améliorer l’API QuerySet pour finalement supprimer extra(). Nous n’améliorons ni ne corrigeons plus de bogues pour cette dernière méthode.

Par exemple, cette utilisation de extra():

>>> qs.extra(
...     select={'val': "select col from sometable where othercol = %s"},
...     select_params=(someparam,),
... )

est équivalent à :

>>> qs.annotate(val=RawSQL("select col from sometable where othercol = %s", (someparam,)))

Le principal avantage d’utiliser RawSQL est qu’il est possible de définir output_field si nécessaire. Le désavantage principal est que si vous faites référence à un alias de table du jeu de requête dans le code SQL brut, il est alors possible que Django modifie cet alias (par exemple lorsque le jeu de requête est utilisé comme sous-requête dans une autre requête).

Avertissement

Vous devez être très prudent lors de l’utilisation de extra(). Lors de chaque utilisation, vous devez échapper tout paramètre pouvant être contrôlé par les utilisateurs en employant params afin de vous protéger contre les attaques par injection SQL. Lisez attentivement les paragraphes sur la protection contre les injections SQL.

Par définition, ces expressions extra ne sont pas toujours portables entre moteurs de base de données (parce que vous écrivez du code SQL explicitement) et elles violent le principe DRY (ne pas se répéter), il s’agit donc de les éviter autant que possible.

Indiquez un ou plusieurs des paramètres params, select, where ou tables. Aucun n’est obligatoire, mais vous devez en indiquer au moins un.

  • select

    Le paramètre select vous permet d’indiquer des champs supplémentaires dans la clause SELECT. Ce doit être un dictionnaire faisant correspondre des noms d’attributs à des clauses SQL utilisées pour calculer l’attribut concerné.

    Exemple :

    Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
    

    Avec ceci, chaque objet Entry possède un attribut supplémentaire, is_recent, une valeur booléenne indiquant si le champ pub_date de l’objet est plus grand que le 1er janvier 2006.

    Django insère l’extrait SQL donné directement dans l’instruction SELECT. Le code SQL résultant de l’exemple ci-dessus ressemblerait donc à ceci :

    SELECT blog_entry.*, (pub_date > '2006-01-01') AS is_recent
    FROM blog_entry;
    

    L’exemple suivant est plus pointu ; il effectue une sous-requête pour donner à chaque objet Blog du résultat un attribut entry_count, un nombre entier comptant les objets Entry associés :

    Blog.objects.extra(
        select={
            'entry_count': 'SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id'
        },
    )
    

    Dans ce cas particulier, nous exploitons le fait que la requête contiendra déjà la table blog_blog dans sa clause FROM.

    Le code SQL résultant de l’exemple ci-dessus donnerait :

    SELECT blog_blog.*, (SELECT COUNT(*) FROM blog_entry WHERE blog_entry.blog_id = blog_blog.id) AS entry_count
    FROM blog_blog;
    

    Notez que les parenthèses exigées par la plupart des moteurs de base de données autour des sous-requêtes ne sont pas obligatoires dans les clauses select de Django. Signalons aussi que certains moteurs de base de données tels que certaines versions de MySQL ne prennent pas en charge les sous-requêtes.

    Dans de rares cas, il peut être souhaitable de passer des paramètres dans les fragments SQL de extra(select=...). Dans ce but, utilisez le paramètre select_params. Comme select_params est une liste et que l’attribut select est un dictionnaire, il faut prendre garde à bien faire correspondre les paramètres aux éléments de sélection supplémentaires. Dans cette situation, il est préférable d’utiliser un dictionnaire collections.OrderedDict pour la valeur select, et pas juste un dictionnaire Python normal.

    Ceci fonctionnera, par exemple :

    Blog.objects.extra(
        select=OrderedDict([('a', '%s'), ('b', '%s')]),
        select_params=('one', 'two'))
    

    Si vous avez besoin d’utiliser un %s littéral à l’intérieur de la chaîne de sélection, utilisez la séquence %%s.

  • where / tables

    Il est possible de définir des clauses SQL WHERE explicites — peut-être pour effectuer des jointures non explicites — en utilisant where. Des tables peuvent être manuellement ajoutées à la clause SQL FROM par le paramètre tables.

    where et tables acceptent tous deux une liste de chaînes de caractères. Tous les paramètres where sont combinés avec les autres critères de recherche par l’opérateur « ET ».

    Exemple :

    Entry.objects.extra(where=["foo='a' OR bar = 'a'", "baz = 'a'"])
    

    …peut être (grossièrement) traduit en code SQL comme :

    SELECT * FROM blog_entry WHERE (foo='a' OR bar='a') AND (baz='a')
    

    Soyez prudent en utilisant le paramètre tables si celui-ci contient des tables déjà utilisées dans le requête. Lorsque vous ajoutez des tables supplémentaires par le paramètre tables, Django suppose que vous voulez que cette table soit ajoutée une fois de plus, si elle s’y trouve déjà. Cela pose un problème, car le nom de table recevra alors un alias. Si une table apparaît plusieurs fois dans une instruction SQL, son nom est remplacé par un alias à partir de la deuxième occurrence, afin que la base de données puisse les différencier. Si alors dans le paramètre where supplémentaire, vous vous référez à la table que vous avez explicitement ajoutée, vous obtiendrez des erreurs.

    En temps normal, seules les tables qui ne font pas encore partie de la requête devraient être ajoutées. Cependant, si le cas ci-dessus se présente, il existe des solutions. Regardez premièrement si vous pouvez éviter d’inclure la table supplémentaire et utiliser celle qui se trouve déjà dans la requête. Si ce n’est pas possible, placez l’appel extra() au début de la construction du jeu de requête afin que la table concernée soit la première occurrence. Finalement, si aucune autre solution ne fonctionne, examinez la requête générée et réécrivez le contenu where afin d’utiliser l’alias attribué à la table supplémentaire. L’alias sera toujours le même tant que vous construisez le jeu de requête de la même manière, il est donc possible de se fier à la stabilité du nom d’alias.

  • order_by

    Si vous avez besoin de trier les résultats de requête à l’aide de nouveaux champs ou tables que vous avez inclus par extra(), utilisez le paramètre order_by de extra() et complétez-le par une liste de chaînes. Celles-ci doivent correspondre soit à des champs de modèles (comme pour la méthode order_by() habituelle des jeux de requête) sous la forme nom_table.nom_colonne, soit à un alias d’une colonne définie dans le paramètre select de extra().

    Par exemple :

    q = Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
    q = q.extra(order_by = ['-is_recent'])
    

    Ce code place en premier dans les résultats tous les éléments pour lesquels is_recent vaut True (dans un tri descendant, True apparaît avant False).

    Par ailleurs, cela montre aussi que vous pouvez appelez extra() plusieurs fois en obtenant le comportement attendu (ajout successif de nouvelles contraintes).

  • params

    Le paramètre where décrit ci-dessus peut utiliser des chaînes de substitution de base de données comme en Python standard, '%s', pour indiquer au moteur de base de données des paramètres qu’il faut automatiquement placer entre guillemets. Le paramètre params est une liste de paramètres supplémentaires à utiliser dans la substitution.

    Exemple :

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    

    Utilisez toujours params au lieu d’insérer des valeurs directement dans la clause where, parce que params garantit que les valeurs seront mises correctement entre guillemets en fonction de la base de données utilisée. Par exemple, les guillemets dans les chaînes seront échappés correctement.

    Faux :

    Entry.objects.extra(where=["headline='Lennon'"])
    

    Juste :

    Entry.objects.extra(where=['headline=%s'], params=['Lennon'])
    

Avertissement

Si vous effectuez des requêtes vers MySQL, notez que le forçage de type silencieux de MySQL peut produire des résultats inattendus lors du mélange de types. Si une requête porte sur une colonne de type chaîne mais contient une valeur nombre entier, MySQL transforme le type de toutes les valeurs de la table en nombre entier avant d’effectuer la comparaison. Par exemple, si la table contient les valeurs 'abc', 'def' et que la requête contient WHERE macolonne=0, les deux lignes seront sélectionnées. Pour empêcher cela, effectuez les transformations de type avant d’utiliser une valeur dans une requête.

defer()

defer(*fields)

Dans certaines situations complexes de structures de données, des modèles peuvent contenir un grand nombre de champs, et certains champs contenir beaucoup de données (par exemple pour les champs texte) ; parfois, la conversion de certaines valeurs en objet Python est coûteuse en performances. Si vous utilisez les résultats d’une requête dans une situation où vous n’êtes pas certain d’avoir besoin de certains champs lors de la requête initiale pour obtenir les données, vous pouvez indiquer à Django de ne pas les récupérer de la base de données.

Ceci se fait en indiquant les noms des champs à ne pas charger dans defer():

Entry.objects.defer("headline", "body")

Un jeu de requête comportant des champs différés renvoie tout de même des instances de modèles. Chaque champ différé sera récupéré de la base de données si vous y faites référence (un à la fois, pas tous les champs différés d’un coup).

On peut appeler plusieurs fois defer(). Chaque appel ajoute les nouveaux champs à l’ensemble des champs différés :

# Defers both the body and headline fields.
Entry.objects.defer("body").filter(rating=5).defer("headline")

L’ordre dans lequel les champs sont ajoutés à l’ensemble différé n’a pas d’importance. L’appel à defer() avec un nom de champ qui a déjà été indiqué comme différé ne pose pas de problème (le champ sera toujours considéré comme différé).

Vous pouvez différer le chargement de champs dans des modèles liés (si les modèles liés sont chargés par select_related()) en utilisant la notation standard de double soulignement pour séparer les champs liés :

Blog.objects.select_related().defer("entry__headline", "entry__body")

Si vous souhaitez effacer l’ensemble des champs différés, indiquez None comme paramètre à defer():

# Load all fields immediately.
my_queryset.defer(None)

Certains champs d’un modèle ne seront pas différés, même si vous demandez de le faire. Le chargement de la clé primaire ne peut jamais être différé. Si vous utilisez select_related() pour récupérer des modèles liés, vous ne devriez pas différer le chargement du champ qui fait la liaison entre le modèle principal et le modèle lié, sous peine d’obtenir une erreur.

Note

La méthode defer() (et sa cousine only() décrite ci-dessous) est réservée aux situations spéciales. Elles permettent d’optimiser après avoir analysé attentivement les requêtes en comprenant exactement les informations nécessaires et après avoir mesuré que la différence entre le chargement des champs utiles ou le chargement de tous les champs du modèle constitue une amélioration significative.

Même si vous pensez que vous vous trouvez dans un cas de situation spéciale, n’utilisez ``defer()`` que si vous ne pouvez pas déterminer au moment de charger la requête si vous aurez besoin des champs supplémentaires ou pas. Si vous chargez et utilisez fréquemment un sous-ensemble particulier de données, la meilleure solution est de normaliser vos modèles et de placer les données non chargées dans un modèle séparé (donc une autre table de base de données). Si les colonnes doivent rester dans une seule table pour une raison précise, créez un modèle avec Meta.managed = False (voir la documentation de l’attribut managed) contenant uniquement les champs que vous avez normalement besoin de charger et utilisez ce modèle là où vous utiliseriez defer(). Cela rend votre code plus explicite, légèrement plus rapide et consomme un petit peu moins de mémoire dans le processus Python.

Par exemple, ces modèles utilisent tous deux la même table de base de données en arrière-plan :

class CommonlyUsedModel(models.Model):
    f1 = models.CharField(max_length=10)

    class Meta:
        managed = False
        db_table = 'app_largetable'

class ManagedModel(models.Model):
    f1 = models.CharField(max_length=10)
    f2 = models.CharField(max_length=10)

    class Meta:
        db_table = 'app_largetable'

# Two equivalent QuerySets:
CommonlyUsedModel.objects.all()
ManagedModel.objects.all().defer('f2')

Si plusieurs champs ont besoin d’être dupliqués dans le modèle non piloté, il peut être préférable de créer un modèle abstrait avec les champs partagés et de faire ensuite hériter les modèles piloté et non piloté de ce modèle abstrait.

Note

Lors de l’appel à save() pour des instances avec champs différés, seuls les champs chargés sont enregistrés. Voir save() pour plus de détails.

only()

only(*fields)

La méthode only() est plus ou moins le contraire de defer(). Il s’agit de l’appeler en indiquant les champs qui ne doivent pas être différés lors du chargement d’un modèle (tous les autres le seront). Si vous avez un modèle dont presque tous les champs doivent être différés, le code peut parfois être simplifié en indiquant l’ensemble complémentaire des champs.

Supposons qu’un modèle possède les champs name, age et biography. Les deux requêtes suivantes sont identiques en terme de champs différés :

Person.objects.defer("age", "biography")
Person.objects.only("name")

À chaque appel de only(), l’ensemble des champs à charger immédiatement est remplacé. Le nom de la méthode est mnémonique : seuls (only en anglais) ces champs sont chargés immédiatement ; les autres sont différés. Ainsi, quand only() est appelé plusieurs fois successivement, seuls les champs du dernier appel sont pris en compte :

# This will defer all fields except the headline.
Entry.objects.only("body", "rating").only("headline")

Comme defer() se comporte de manière incrémentale (ajoutant les champs à la liste différée), vous pouvez combiner les appels à only() et defer() et tout devrait se passer comme prévu :

# Final result is that everything except "headline" is deferred.
Entry.objects.only("headline", "body").defer("body")

# Final result loads headline and body immediately (only() replaces any
# existing set of fields).
Entry.objects.defer("body").only("headline", "body")

Tous les avertissements de la note de la documentation de defer() s’appliquent également à only(). Utilisez-la prudemment et seulement après avoir épuisé les autres options possibles.

L’utilisation d’only() en omettant un champ demandé par select_related() constitue aussi une erreur.

Note

Lors de l’appel à save() pour des instances avec champs différés, seuls les champs chargés sont enregistrés. Voir save() pour plus de détails.

using()

using(alias)

Cette méthode sert à contrôler la base de données qui sera la cible d’évaluation du QuerySet dans le cas où plusieurs bases de données sont définies. Le seul paramètre admis par cette méthode est l’alias d’une base de données, tel que défini dans DATABASES.

Par exemple :

# queries the database with the 'default' alias.
>>> Entry.objects.all()

# queries the database with the 'backup' alias
>>> Entry.objects.using('backup')

select_for_update()

select_for_update(nowait=False)

Renvoie un jeu de requête qui verrouille les lignes jusqu’à la fin de la transaction, générant une instruction SQL SELECT ... FOR UPDATE pour les bases de données qui la prennent en charge.

Par exemple :

entries = Entry.objects.select_for_update().filter(author=request.user)

Toutes les lignes de base de données correspondantes sont verrouillées jusqu’à la fin du bloc transactionnel, ce qui veut dire que d’autres transactions ne pourront ni modifier ni verrouiller elles-mêmes ces lignes.

Normalement, si une autre transaction a déjà verrouillé l’une des lignes sélectionnées, la requête est bloquée en attendant que le verrou soit levé. Si ce n’est pas ce que vous voulez, appelez select_for_update(nowait=True). L’appel est alors non bloquant. Si un verrou est déjà posé par une autre transaction sur un des éléments à sélectionner, une exception DatabaseError est générée lors de l’évaluation du jeu de requête.

En ce moment, les moteurs de base de données postgresql, oracle et mysql prennent en charge select_for_update(). Cependant, MySQL ne gère pas le paramètre nowait. Si vous utilisez d’autres moteurs de tierce partie, vérifiez les détails de ce cas de figure dans la documentation du moteur.

Si vous passez nowait=True à select_for_update() et que le moteur de base de données ne prend pas en charge nowait, comme pour MySQL, une exception DatabaseError sera générée. Ceci permet d’éviter que du code soit bloqué de manière inattendue.

L’évaluation d’un jeu de requête avec select_for_update() en mode autocommit avec les bases de données qui prennent en charge SELECT ... FOR UPDATE est une erreur TransactionManagementError, car dans ce cas-là, les lignes ne sont pas verrouillées. Si c’était permis, ce serait un vecteur de corruption de données qui pourrait facilement être provoqué par l’appel de code conçu pour être exécuté dans une transaction en dehors d’une transaction.

L’emploi de select_for_update() avec des moteurs qui ne prennent pas en charge SELECT ... FOR UPDATE (comme pour SQLite) n’aura aucun effet. SELECT ... FOR UPDATE ne sera pas ajouté à la requête et aucune erreur ne sera produite si select_for_update() est utilisé en mode autocommit.

Avertissement

Même si select_for_update() échoue normalement en mode autocommit, puisque TestCase englobe automatiquement chaque test dans une transaction, l’appel à select_for_update() dans un TestCase même en dehors d’un bloc atomic() va passer (peut-être de façon inattendue) sans générer d’exception TransactionManagementError. Pour tester convenablement select_for_update(), vous devez utiliser TransactionTestCase.

raw()

raw(raw_query, params=None, translations=None)

Accepte une requête SQL brute, l’exécute et renvoie une instance django.db.models.query.RawQuerySet. Il est possible alors d’effectuer une boucle sur cette instance RawQuerySet tout comme pour un objet QuerySet normal afin d’accéder aux instances d’objets.

Voir Lancement de requêtes SQL brutes pour plus d’informations.

Avertissement

raw() génère toujours une nouvelle requête et ne tient pas compte d’éventuels filtrages précédents. Ainsi, elle ne devrait généralement être appelée que depuis un Manager ou une instance QuerySet toute neuve.

Méthodes qui ne renvoient pas de QuerySet

Les méthodes de QuerySet suivantes évaluent le QuerySet et renvoie quelque chose d’autre qu’un QuerySet.

Ces méthodes n’utilisent pas de cache (voir Mise en cache et objets QuerySet). Elles accèdent à la base de données lors de chaque appel.

get()

get(**kwargs)

Renvoie l’objet correspondant aux paramètres de recherche indiqués, qui doivent être dans le format décrit dans Recherches dans les champs.

get() génère MultipleObjectsReturned si plus d’un objet est renvoyé. L’exception MultipleObjectsReturned est un attribut de la classe de modèle.

get() génère l’exception DoesNotExist si aucun objet ne correspond aux paramètres données. Cette exception est un attribut de la classe de modèle. Exemple :

Entry.objects.get(id='foo') # raises Entry.DoesNotExist

L’exception DoesNotExist hérite de django.core.exceptions.ObjectDoesNotExist, il est donc possible de cibler plusieurs exceptions DoesNotExist. Exemple :

from django.core.exceptions import ObjectDoesNotExist
try:
    e = Entry.objects.get(id=3)
    b = Blog.objects.get(id=1)
except ObjectDoesNotExist:
    print("Either the entry or blog doesn't exist.")

Si vous pensez qu’une requête ne renverra qu’une ligne, vous pouvez utiliser get() sans paramètre pour obtenir l’objet correspondant à cette ligne :

entry = Entry.objects.filter(...).exclude(...).get()

create()

create(**kwargs)

Une méthode d’agrément pour la création d’un objet et son enregistrement en une seule méthode. Ainsi :

p = Person.objects.create(first_name="Bruce", last_name="Springsteen")

et :

p = Person(first_name="Bruce", last_name="Springsteen")
p.save(force_insert=True)

sont équivalents.

Le paramètre force_insert est documenté ailleurs, mais il indique qu’un nouvel objet sera toujours créé. Vous n’avez normalement pas à vous préoccuper de ce paramètre. Cependant, si le modèle contient une valeur de clé primaire que vous avez définie manuellement et que cette valeur existe déjà en base de données, l’appel à create() échoue avec l’erreur IntegrityError car les clés primaires doivent rester uniques. Soyez prêt à traiter l’exception si vous définissez manuellement des clés primaires.

get_or_create()

get_or_create(defaults=None, **kwargs)

Une méthode utile pour rechercher un objet correspondant aux paramètres kwargs indiqués (qui peuvent être vides si le modèle contient des valeurs par défaut pour tous les champs), et qui crée un objet si nécessaire.

Renvoie un tuple (objet, créé)objet est l’objet chargé ou créé et créé est une valeur booléenne indiquant si un nouvel objet a été créé.

L’intention est de fournir un raccourci à la place de code répétitif. Par exemple :

try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
    obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
    obj.save()

Cette pratique devient de plus en plus lourde en fonction de la quantité de champs d’un modèle. L’exemple ci-dessus peut être réécrit en utilisant get_or_create(), comme ceci :

obj, created = Person.objects.get_or_create(
    first_name='John',
    last_name='Lennon',
    defaults={'birthday': date(1940, 10, 9)},
)

Tout paramètre nommé transmis à get_or_create(), à l’exception d’un paramètre facultatif nommé defaults, sera utilisé dans un appel à get(). Si un objet correspond, get_or_create() renvoie un tuple contenant cet objet et False. Si plusieurs objets correspondent, get_or_create génère une exception MultipleObjectsReturned. Si aucun objet ne correspond, get_or_create() crée et enregistre une nouvelle instance d’objet, renvoyant un tuple contenant le nouvel objet et True. Le nouvel objet est créé en suivant grossièrement cet algorithme :

params = {k: v for k, v in kwargs.items() if '__' not in k}
params.update(defaults)
obj = self.model(**params)
obj.save()

En français, cela veut dire qu’on commence par tout paramètre nommé autre que 'defaults' et qui ne contient pas de double soulignement (ce qui indiquerait une recherche non exacte). Puis on ajoute le contenu de 'defaults', surchargeant d’éventuels paramètres existants, et on utilise le résultat comme paramètres nommés de la classe de modèle. Comme déjà dit, il s’agit d’une simplification de l’algorithme réel, mais tous les éléments importants sont là. L’implémentation réelle contient quelques contrôles d’erreur supplémentaires et traite quelques conditions extrêmes ; si cela vous intéresse, lisez le code.

Si vous avez un champ nommé defaults et que vous voulez l’utiliser comme recherche exacte dans get_or_create(), il suffit d’indiquer 'defaults__exact', comme ceci :

Foo.objects.get_or_create(defaults__exact='bar', defaults={'defaults': 'baz'})

Le comportement d’erreur de la méthode get_or_create() est semblable à celui de create() lorsque vous définissez des clés primaires manuellement. Si un objet doit être créé et que la clé primaire existe déjà en base de données, une exception IntegrityError est générée.

Cette méthode est atomique si on l’utilise correctement, avec une configuration correcte de base de données et un comportement correct de la base de données elle-même. Cependant, si l’unicité n’est pas garantie au niveau de la base de données pour les paramètres kwargs utilisés dans un appel à get_or_create (voir unique ou unique_together), cette méthode est sujette à un conflit de concurrence pouvant résulter en plusieurs lignes identiques insérées simultanément.

Si vous utilisez MySQL, assurez-vous d’utiliser le niveau d’isolation READ COMMITTED plutôt que REPEATABLE READ (valeur par défaut), sinon il est possible que get_or_create génère une exception IntegrityError sans que l’objet n’apparaisse dans un appel get() ultérieur.

Pour terminer, un mot sur l’utilisation de get_or_create() dans les vues Django. Faites attention de ne l’utiliser que dans des requêtes POST, sauf si vous avez des bonnes raisons de faire autrement. Les requêtes GET ne sont pas censées modifier des données. Il faudrait toujours utiliser POST lorsqu’une requête sur une page provoque des effets de bord sur les données. Pour plus de détails, lisez Safe methods dans la spécification HTTP.

Avertissement

Vous pouvez utiliser get_or_create() au travers d’attributs ManyToManyField et de relations inverses. Dans ce cas, vous allez restreindre les requêtes dans le contexte de cette relation. Certains problèmes d’intégrité peuvent apparaître si vous ne l’utilisez pas de manière cohérente.

Compte tenu des modèles suivants :

class Chapter(models.Model):
    title = models.CharField(max_length=255, unique=True)

class Book(models.Model):
    title = models.CharField(max_length=256)
    chapters = models.ManyToManyField(Chapter)

Vous pouvez utiliser get_or_create() au travers du champ chapters de Book, mais il ne considère alors que les objets dans le contexte de ce Book:

>>> book = Book.objects.create(title="Ulysses")
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, True)
>>> book.chapters.get_or_create(title="Telemachus")
(<Chapter: Telemachus>, False)
>>> Chapter.objects.create(title="Chapter 1")
<Chapter: Chapter 1>
>>> book.chapters.get_or_create(title="Chapter 1")
# Raises IntegrityError

Cela se passe ainsi parce qu’il essaie d’obtenir ou de créer « Chapter 1 » au travers du livre « Ulysses », mais il ne peut faire ni l’un ni l’autre : la relation ne peut pas obtenir ce chapitre puisqu’il ne se trouve pas dans ce livre, mais il ne peut pas non plus le créer car le champ title doit être unique.

update_or_create()

update_or_create(defaults=None, **kwargs)

Une méthode utilitaire pour mettre à jour un objet avec les paramètres kwargs donnés, en créant un nouvel objet si nécessaire. Le paramètre defaults est un dictionnaire de paires (champ, valeur) utilisé pour mettre à jour l’objet.

Renvoie un tuple (objet, créé)objet est l’objet créé ou mis à jourcréé et créé est une valeur booléenne indiquant si un nouvel objet a été créé.

La méthode update_or_create essaie de récupérer un objet de la base de données en fonction des paramètres kwargs indiqués. Si une correspondance est trouvée, elle met à jour les champs transmis dans le dictionnaire defaults.

L’intention est de fournir un raccourci à la place de code répétitif. Par exemple :

defaults = {'first_name': 'Bob'}
try:
    obj = Person.objects.get(first_name='John', last_name='Lennon')
    for key, value in defaults.items():
        setattr(obj, key, value)
    obj.save()
except Person.DoesNotExist:
    new_values = {'first_name': 'John', 'last_name': 'Lennon'}
    new_values.update(defaults)
    obj = Person(**new_values)
    obj.save()

Ce schéma devient tendancieux au fur et à mesure que le nombre de champs d’un modèle augmente. L’exemple ci-dessus peut être réécrit en utilisant update_or_create() comme ceci :

obj, created = Person.objects.update_or_create(
    first_name='John', last_name='Lennon',
    defaults={'first_name': 'Bob'},
)

Pour une description détaillée sur la manière dont les noms transmis dans kwargs sont résolus, voir get_or_create().

Comme expliqué plus haut pour get_or_create(), cette méthode est sujette à un conflit de concurrence qui peut aboutir à l’insertion simultanée de plusieurs lignes si l’unicité n’est pas garantie au niveau de la base de données.

bulk_create()

bulk_create(objs, batch_size=None)

Cette méthode insère la liste d’objets indiquée dans la base de données de manière efficace (généralement par une seule requête, quel que soit le nombre d’objets concernés) :

>>> Entry.objects.bulk_create([
...     Entry(headline='This is a test'),
...     Entry(headline='This is only a test'),
... ])

Cette méthode présente toutefois quelques inconvénients :

  • La méthode save() de chaque modèle n’est pas appelée et les signaux pre_save et post_save ne sont pas envoyés.

  • Elle ne fonctionne pas avec des modèles enfants dans un contexte d’héritage multitable.

  • Si la clé primaire du modèle est un champ AutoField, elle ne récupère pas ni ne définit l’attribut de clé primaire, comme le fait save(), sauf si le moteur de base de données le gère (actuellement PostgreSQL).

  • Elle ne fonctionne pas avec les relations plusieurs-à-plusieurs.

Changed in Django 1.9:

La prise en charge de bulk_create() avec des modèles mandataires a été ajoutée.

Changed in Django 1.10:

La prise en charge de la définition des clés primaires pour les objets créés avec bulk_create() en utilisant PostgreSQL a été ajoutée.

Le paramètre batch_size permet de contrôler le nombre d’objets créés dans une seule requête. Par défaut, tous les objets sont créés en une seule instruction, à l’exception de SQLite où par défaut, le nombre maximum de 999 variables par requête est appliqué.

count()

count()

Renvoie un nombre entier représentant le nombre d’objets de base de données correspondant au QuerySet. La méthode count() ne produit jamais d’exception.

Exemple :

# Returns the total number of entries in the database.
Entry.objects.count()

# Returns the number of entries whose headline contains 'Lennon'
Entry.objects.filter(headline__contains='Lennon').count()

Un appel à count() génère une instruction SELECT COUNT(*) en arrière-plan, il est donc conseiller de toujours utiliser count() plutôt que de charger tous les résultats en objets Python et d’appeler len() sur cette liste d’objets (sauf dans le cas où vous avez de toute façon besoin de charger les objets en mémoire, auquel cas len() sera plus rapide).

En fonction du type de base de données utilisé (par ex. PostgreSQL vs. MySQL), il est possible que count() renvoie un entier long au lieu d’un nombre entier Python normal. Il s’agit d’un détail d’implémentation qui ne devrait pas poser de problème en réalité.

Notez que si vous souhaitez obtenir le nombre d’élément d’un QuerySet et que vous allez aussi exploiter ses instances de modèles (par exemple dans une itération), il est probablement plus efficace d’utiliser len(queryset) qui ne produira pas de requête de base de données supplémentaire comme le ferait count().

in_bulk()

in_bulk(id_list=None)

Accepte une liste de valeurs de clés primaires et renvoie un dictionnaire faisant correspondre chaque valeur de clé primaire à une instance d’objet dont la clé primaire correspond. Si aucune liste n’est fournie, tous les objets du jeu de requête sont renvoyés.

Exemple :

>>> Blog.objects.in_bulk([1])
{1: <Blog: Beatles Blog>}
>>> Blog.objects.in_bulk([1, 2])
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>}
>>> Blog.objects.in_bulk([])
{}
>>> Blog.objects.in_bulk()
{1: <Blog: Beatles Blog>, 2: <Blog: Cheddar Talk>, 3: <Blog: Django Weblog>}

En passant une liste vide à in_bulk(), le résultat est un dictionnaire vide.

Changed in Django 1.10:

Dans les versions précédentes, id_list était un paramètre obligatoire.

iterator()

iterator()

Évalue le QuerySet (en exécutant la requête) et renvoie un itérateur (voir PEP 234) sur les résultats. Un QuerySet met typiquement en cache interne ses résultats afin que d’éventuelles autres évaluations ne produisent pas de requête supplémentaire. Au contraire, iterator() lit directement les résultats, sans rien mettre dans le cache du QuerySet (en interne, l’itérateur par défaut appelle iterator() et met en cache la valeur renvoyée). Pour un QuerySet renvoyant un grand nombre d’objets que vous ne devez accéder qu’une seule fois, cela peut amener à de meilleures performances et à une utilisation bien moindre de la mémoire.

Notez que l’utilisation de iterator() sur un QuerySet ayant déjà été évalué force une nouvelle évaluation en répétant la requête.

De plus, l’utilisation de``iterator()`` ignore d’éventuels appels précédents à prefetch_related(), car il n’est pas logique de combiner ces deux optimisations.

Avertissement

Certains pilotes de base de données Python comme psycopg2 exploitent un cache lors de l’utilisation de curseurs clients (créés par connection.cursor(), ce que l’ORM de Django effectue). L’utilisation de iterator() n’a pas d’influence sur le cache au niveau du pilote de la base de données. Pour désactiver ce dernier, référez-vous à Curseurs côté serveur.

latest()

latest(field_name=None)

Renvoie le dernier objet de la table, en fonction de sa date et en se basant sur field_name, le nom du champ date pris en compte.

Cet exemple renvoie le dernier objet Entry de la table, selon le champ pub_date:

Entry.objects.latest('pub_date')

Si la classe Meta d’un modèle définit get_latest_by, il est possible d’omettre le paramètre field_name de earliest() et latest(). Django utilise par défaut le champ défini dans get_latest_by.

Comme get(), earliest() et latest() génèrent DoesNotExist si aucun objet ne correspond aux paramètres donnés.

Notez que earliest() et latest() n’existent que par commodité et pour une meilleure lisibilité.

earliest() et latest() peuvent renvoyer des instances avec des dates nulles.

Comme le tri est délégué à la base de données, les résultats des champs qui autorisent les valeurs nulles peuvent être triés différemment en fonction de la base de données. Par exemple, PostgreSQL et MySQL trient les valeurs nulles comme si elles étaient plus élevées que les valeurs non nulles, alors que SQLite fait l’inverse.

Il peut être souhaitable d’exclure les valeurs nulles :

Entry.objects.filter(pub_date__isnull=False).latest('pub_date')

earliest()

earliest(field_name=None)

Fonctionne comme latest(), mais dans le sens inverse.

first()

first()

Renvoie le premier objet du jeu de requête, ou None si la requête est vide. Si l’objet QuerySet n’est pas trié, la requête est automatiquement triée selon la clé primaire.

Exemple :

p = Article.objects.order_by('title', 'pub_date').first()

Notez que first() est une méthode d’agrément ; l’extrait de code suivant est équivalent à l’exemple ci-dessus :

try:
    p = Article.objects.order_by('title', 'pub_date')[0]
except IndexError:
    p = None

last()

last()

Fonctionne comme first(), mais renvoie le dernier objet du jeu de requête.

aggregate()

aggregate(*args, **kwargs)

Renvoie un dictionnaire de valeurs agrégées (moyennes, sommes, etc.) calculées dans le QuerySet. Chaque paramètre d’aggregate() définit une valeur qui sera incluse dans le dictionnaire renvoyé.

Les fonctions d’agrégation fournies par Django sont décrites plus loin dans Fonctions d’agrégation. Comme les agrégations sont aussi des expressions de requête, il est possible de combiner des agrégations avec d’autres agrégations ou valeurs afin de créer des agrégations complexes.

Les agrégations spécifiées par des paramètres nommés utilisent la clé comme nom d’annotation. Les paramètres anonymes seront dotés d’un nom généré automatiquement sur la base du nom de la fonction d’agrégation et du champ de modèle sur lequel porte l’agrégation. Les agrégations complexes ne peuvent pas utiliser de paramètres anonymes et doivent indiquer un paramètre nommé jouant le rôle d’alias.

Par exemple, si vous avez affaire à des articles de blog, il peut être intéressant de déterminer le nombre d’auteurs ayant écrits des articles :

>>> from django.db.models import Count
>>> q = Blog.objects.aggregate(Count('entry'))
{'entry__count': 16}

En utilisant un paramètre nommé pour définir la fonction d’agrégation, vous pouvez contrôler le nom de la valeur d’agrégation dans le résultat :

>>> q = Blog.objects.aggregate(number_of_entries=Count('entry'))
{'number_of_entries': 16}

Pour une présentation approfondie de l’agrégation, consultez le guide thématique sur l’agrégation.

exists()

exists()

Renvoie True si le QuerySet contient au moins un résultat, sinon False. Cette méthode s’efforce de lancer la requête la plus simple et rapide possible, mais la requête exécutée est quasi identique à celle du QuerySet normal.

exists() est utile pour des recherches liées à l’appartenance d’objets dans un QuerySet et à l’existence d’au moins un objet dans un QuerySet, particulièrement dans le contexte de QuerySet volumineux.

La méthode la plus efficace pour déterminer si un modèle avec un champ unique (par ex. sa clé primaire) est présent dans un QuerySet est :

entry = Entry.objects.get(pk=123)
if some_queryset.filter(pk=entry.pk).exists():
    print("Entry contained in queryset")

Ce qui sera plus rapide que l’exemple suivant qui demande l’évaluation et l’itération de la totalité du jeu de requête :

if entry in some_queryset:
   print("Entry contained in QuerySet")

Et pour savoir si un jeu de requête contient au moins un élément :

if some_queryset.exists():
    print("There is at least one object in some_queryset")

Ce qui sera plus rapide que :

if some_queryset:
    print("There is at least one object in some_queryset")

…mais pas de beaucoup (plus le jeu de requête est potentiellement volumineux, plus le gain sera élevé).

De plus, si some_queryset n’a pas encore été évalué mais que vous savez qu’il le sera à un moment donné, l’appel à some_queryset.exists() effectue du travail en plus (une requête pour le contrôle d’existence, plus une autre plus tard au moment de charger les résultats) par rapport au simple bool(some_queryset), qui récupère les résultats et vérifie ensuite s’il y en a au moins un.

update()

update(**kwargs)

Effectue une requête de mise à jour SQL pour les champs indiqués et renvoie le nombre de lignes affectées (qui n’est pas forcément égal au nombre de lignes mises à jour dans la mesure où certaines lignes possèdent déjà la nouvelle valeur).

Par exemple, pour désactiver les commentaires pour tous les articles de blog publiés en 2010, vous pourriez écrire cela :

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)

(En supposant que votre modèle Entry contienne les champs pub_date et comments_on.)

Vous pouvez mettre à jour plusieurs champs ; il n’y a pas de limite. Dans l’exemple suivant, nous mettons à jour les champs comments_on et headline:

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False, headline='This is old')

La méthode update() est appliquée immédiatement et la seule restriction sur le QuerySet de mise à jour est qu’il ne peut mettre à jour que des colonnes de la table principale du modèle, pas dans des modèles liés. Par exemple, ceci n’est pas possible :

>>> Entry.objects.update(blog__name='foo') # Won't work!

Le filtrage basé sur des champs liés est cependant toujours possible :

>>> Entry.objects.filter(blog__id=1).update(comments_on=True)

Vous ne pouvez pas appeler update() sur un QuerySet qui a subi une segmentation ou qui ne peut plus être filtré pour une autre raison.

La méthode update() renvoie le nombre de lignes affectées :

>>> Entry.objects.filter(id=64).update(comments_on=True)
1

>>> Entry.objects.filter(slug='nonexistent-slug').update(comments_on=True)
0

>>> Entry.objects.filter(pub_date__year=2010).update(comments_on=False)
132

Si vous n’avez qu’une ligne à mettre à jour et que vous n’avez rien à faire de spécial avec l’objet modèle, l’approche la plus efficace est d’appeler update(), plutôt que de charger en mémoire l’objet modèle. Par exemple, au lieu de faire cela :

e = Entry.objects.get(id=10)
e.comments_on = False
e.save()

…faites ceci :

Entry.objects.filter(id=10).update(comments_on=False)

L’utilisation d’update() permet aussi d’éviter une situation de concurrence où le contenu en base de données pourrait être modifié dans le court intervalle entre le chargement de l’objet et l’appel à save().

Finalement, réalisez que update() effectue la mise à jour au niveau SQL et par conséquent, n’appelle pas la méthode save() des modèles et n’émet pas non plus les signaux pre_save et post_save (qui sont une conséquence de l’appel à Model.save()). Si vous souhaitez mettre à jour un certain nombre d’objets d’un modèle possédant une méthode save() personnalisée, passez-les dans une boucle en appelant save(), comme ceci :

for e in Entry.objects.filter(pub_date__year=2010):
    e.comments_on = False
    e.save()

delete()

delete()

Effectue une requête de suppression SQL de toutes les lignes de QuerySet et renvoie le nombre d’objets supprimés ainsi qu’un dictionnaire avec le nombre de suppressions par type d’objet.

La suppression delete() s’applique immédiatement. Vous ne pouvez pas appeler delete() sur un QuerySet qui a subi une segmentation ou qui ne peut plus être filtré pour une autre raison.

Par exemple, pour supprimer tous les articles d’un blog particulier :

>>> b = Blog.objects.get(pk=1)

# Delete all the entries belonging to this Blog.
>>> Entry.objects.filter(blog=b).delete()
(4, {'weblog.Entry': 2, 'weblog.Entry_authors': 2})
Changed in Django 1.9:

La valeur renvoyée contenant le nombre d’objets supprimés a été ajoutée.

Par défaut, les champs ForeignKey de Django émulent le comportement de la contrainte SQL ON DELETE CASCADE. En d’autres termes, tout objet possédant des clés étrangères vers les objets en cours de suppression seront également supprimés. Par exemple :

>>> blogs = Blog.objects.all()

# This will delete all Blogs and all of their Entry objects.
>>> blogs.delete()
(5, {'weblog.Blog': 1, 'weblog.Entry': 2, 'weblog.Entry_authors': 2})

Ce comportement en cascade peut être personnalisé par le paramètre on_delete de ForeignKey.

La méthode delete() supprime en vrac et n’appelle pas la méthode delete() des modèles. Par contre, elle émet les signaux pre_delete et post_delete pour tous les objets supprimés (y compris les suppressions en cascade).

Django a besoin de charger les objets en mémoire pour envoyer les signaux et gérer les suppressions en cascade. Cependant, s’il n’y a pas d’objets en cascade ni de signaux, Django se permet de choisir une voie rapide et de supprimer les objets sans les charger en mémoire. Pour des grosses suppressions, cela peut réduire considérablement la consommation mémoire. Le nombre de requêtes exécutées peut également être plus faible.

Les clés étrangères dont le paramètre on_delete vaut DO_NOTHING (ne rien faire) n’empêchent pas la suppression accélérée.

Notez que les requêtes générées lors de la suppression d’objets constituent un détail d’implémentation susceptible d’être modifié.

as_manager()

classmethod as_manager()

Méthode de classe qui renvoie une instance de Manager avec une copie des méthodes de QuerySet. Voir Création d’objet Manager avec des méthodes de QuerySet pour plus de détails.

Recherches dans les champs

La recherche dans les champs est ce qui constitue le cœur des clauses SQL WHERE. La syntaxe s’exprime par des paramètres nommés dans les méthodes filter(), exclude() et get() de QuerySet.

Pour une introduction sur ce sujet, consultez la documentation sur les requêtes de modèles et de base de données.

Les recherches fournies par Django sont présentées ci-dessous. Il est également possible d’écrire des recherches personnalisées pour les champs de modèles.

Par commodité, lorsqu’aucune recherche particulière n’est indiquée (comme dans Entry.objects.get(id=14)), Django suppose que la recherche souhaitée est exact.

exact

Correspondance exacte. Si la valeur fournie pour la comparaison vaut None, elle sera interprétée comme un NULL SQL (voir isnull pour plus de détails).

Exemples :

Entry.objects.get(id__exact=14)
Entry.objects.get(id__exact=None)

Équivalence en SQL :

SELECT ... WHERE id = 14;
SELECT ... WHERE id IS NULL;

Comparaisons MySQL

Avec MySQL, le paramètre « collation » d’une table de base de données détermine si les comparaisons exact sont sensibles à la casse. Il s’agit d’un réglage de base de données, pas de Django. Il est possible de configurer vos tables MySQL afin qu’elles utilisent des comparaisons sensibles à la casse, mais cela implique certains compromis. Pour plus d’informations à ce sujet, consultez la section collation dans la documentation des bases de données.

iexact

Correspondance exacte insensible à la casse. Si la valeur fournie pour la comparaison vaut None, elle sera interprétée comme un NULL SQL (voir isnull pour plus de détails).

Exemple :

Blog.objects.get(name__iexact='beatles blog')
Blog.objects.get(name__iexact=None)

Équivalence en SQL :

SELECT ... WHERE name ILIKE 'beatles blog';
SELECT ... WHERE name IS NULL;

Notez que 'Beatles Blog', 'beatles blog', 'BeAtLes BLoG', etc. correspondent tous à la première recherche.

Utilisateurs de SQLite

Lors de l’utilisation du moteur SQLite et de chaînes Unicode (non ASCII), il faut tenir compte des notes de base de données au sujet de la comparaison de chaînes. SQLite n’effectue pas de recherches insensibles à la casse pour des chaînes Unicode.

contains

Test d’inclusion sensible à la casse.

Exemple :

Entry.objects.get(headline__contains='Lennon')

Équivalence en SQL :

SELECT ... WHERE headline LIKE '%Lennon%';

Notez que le titre (headline) 'Lennon honored today' correspondrait à cette recherche, mais pas 'lennon honored today'.

Utilisateurs de SQLite

SQLite ne prend pas en charge les instructions LIKE sensibles à la casse ; contains se comporte comme icontains pour SQLite. Consultez les notes de bases de données pour plus d’informations.

icontains

Test d’inclusion insensible à la casse.

Exemple :

Entry.objects.get(headline__icontains='Lennon')

Équivalence en SQL :

SELECT ... WHERE headline ILIKE '%Lennon%';

Utilisateurs de SQLite

Lors de l’utilisation du moteur SQLite et de chaînes Unicode (non ASCII), il faut tenir compte des notes de base de données au sujet de la comparaison de chaînes.

in

Inclusion dans une liste.

Exemple :

Entry.objects.filter(id__in=[1, 3, 4])

Équivalence en SQL :

SELECT ... WHERE id IN (1, 3, 4);

Vous pouvez également utiliser un jeu de requête pour évaluer dynamiquement la liste des valeurs au lieu de fournir une liste de valeurs littérales :

inner_qs = Blog.objects.filter(name__contains='Cheddar')
entries = Entry.objects.filter(blog__in=inner_qs)

Ce jeu de requête sera évalué sous forme d’instruction de sous-sélection :

SELECT ... WHERE blog.id IN (SELECT id FROM ... WHERE NAME LIKE '%Cheddar%')

Si vous fournissez un QuerySet résultant d’un appel à values() ou à values_list() comme valeur d’une requête __in, vous devez vous assurer que vous extrayez un seul champ du résultat. Par exemple, ceci fonctionnera (filtrage sur les noms de blogs) :

inner_qs = Blog.objects.filter(name__contains='Ch').values('name')
entries = Entry.objects.filter(blog__name__in=inner_qs)

Cet exemple générera une exception, car la requête imbriquée extrait deux valeurs de champ, alors qu’il n’en faut qu’une seule :

# Bad code! Will raise a TypeError.
inner_qs = Blog.objects.filter(name__contains='Ch').values('name', 'id')
entries = Entry.objects.filter(blog__name__in=inner_qs)

Considérations sur la performance

Soyez prudent avec les requêtes imbriquées ; il s’agit de bien comprendre les enjeux au niveau des performances du serveur de base de données (en cas de doute, faites des tests de performance). Certains moteurs de base de données, plus particulièrement MySQL, n’optimisent pas très bien les sous-requêtes. Dans ces situations, il est plus efficace d’extraire les valeurs sous forme de liste puis de les transmettre à la seconde requête. En clair, effectuer deux requêtes au lieu d’une seule :

values = Blog.objects.filter(
        name__contains='Cheddar').values_list('pk', flat=True)
entries = Entry.objects.filter(blog__in=list(values))

Remarquez l’appel list() autour du QuerySet Blog pour forcer l’exécution de la première requête. Sans cela, une sous-requête serait exécutée, car Les objects QuerySet sont différés.

gt

Plus grand que.

Exemple :

Entry.objects.filter(id__gt=4)

Équivalence en SQL :

SELECT ... WHERE id > 4;

gte

Plus grand ou égal à.

lt

Plus petit que.

lte

Plus petit ou égal à.

startswith

Commence par (sensible à la casse).

Exemple :

Entry.objects.filter(headline__startswith='Will')

Équivalence en SQL :

SELECT ... WHERE headline LIKE 'Will%';

SQLite ne prend pas en charge les instructions LIKE sensibles à la casse ; startswith se comporte comme istartswith pour SQLite.

istartswith

Commence par (non sensible à la casse).

Exemple :

Entry.objects.filter(headline__istartswith='will')

Équivalence en SQL :

SELECT ... WHERE headline ILIKE 'Will%';

Utilisateurs de SQLite

Lors de l’utilisation du moteur SQLite et de chaînes Unicode (non ASCII), il faut tenir compte des notes de base de données au sujet de la comparaison de chaînes.

endswith

Se termine par (sensible à la casse).

Exemple :

Entry.objects.filter(headline__endswith='cats')

Équivalence en SQL :

SELECT ... WHERE headline LIKE '%cats';

Utilisateurs de SQLite

SQLite ne prend pas en charge les instructions LIKE sensibles à la casse ; endswith se comporte comme iendswith pour SQLite. Consultez les notes de bases de données pour plus d’informations.

iendswith

Se termine par (non sensible à la casse).

Exemple :

Entry.objects.filter(headline__iendswith='will')

Équivalence en SQL :

SELECT ... WHERE headline ILIKE '%will'

Utilisateurs de SQLite

Lors de l’utilisation du moteur SQLite et de chaînes Unicode (non ASCII), il faut tenir compte des notes de base de données au sujet de la comparaison de chaînes.

range

Test d’intervalle (inclusif).

Exemple :

import datetime
start_date = datetime.date(2005, 1, 1)
end_date = datetime.date(2005, 3, 31)
Entry.objects.filter(pub_date__range=(start_date, end_date))

Équivalence en SQL :

SELECT ... WHERE pub_date BETWEEN '2005-01-01' and '2005-03-31';

Vous pouvez utiliser range partout là ou vous pouvez utiliser BETWEEN en SQL — pour les dates, les nombres et même les caractères.

Avertissement

Le filtrage sur un champ DateTimeField avec des dates n’inclura pas les objets du dernier jour, car les limites sont interprétées comme « minuit à la date indiquée ». Si pub_date était un champ DateTimeField, l’expression ci-dessus correspondrait au code SQL suivant :

SELECT ... WHERE pub_date BETWEEN '2005-01-01 00:00:00' and '2005-03-31 00:00:00';

De manière générale, il n’est pas possible de mélanger des objets dates et dates/heures.

date

New in Django 1.9.

Pour les champs date/heure, force la valeur à une date. Cette expression peut être suivie d’autres expressions de champs. Accepte une valeur date.

Exemple :

Entry.objects.filter(pub_date__date=datetime.date(2005, 1, 1))
Entry.objects.filter(pub_date__date__gt=datetime.date(2005, 1, 1))

(Nous n’avons pas inclus de code SQL équivalent pour cette recherche car l’implémentation de la requête correspondante varie beaucoup selon le moteur de base de données.)

Lorsque USE_TZ vaut True, les champs sont convertis dans le fuseau horaire en cours avant le filtrage.

year

Pour les champs date et date/heure, une correspondance exacte de l’année. Cette expression peut être suivie d’autres expressions de champs. Accepte une année comme nombre entier.

Exemple :

Entry.objects.filter(pub_date__year=2005)
Entry.objects.filter(pub_date__year__gte=2005)

Équivalence en SQL :

SELECT ... WHERE pub_date BETWEEN '2005-01-01' AND '2005-12-31';
SELECT ... WHERE pub_date >= '2005-01-01';

(La syntaxe SQL exacte varie d’un moteur de base de données à l’autre.)

Lorsque USE_TZ vaut True, les champs date/heure sont convertis dans le fuseau horaire en cours avant le filtrage.

Changed in Django 1.9:

Possibilité de faire suivre l’expression par d’autres expressions de champs.

month

Pour les champs date et date/heure, une correspondance exacte du mois. Cette expression peut être suivie d’autres expressions de champs. Accepte un nombre entier, de 1 (janvier) à 12 (décembre).

Exemple :

Entry.objects.filter(pub_date__month=12)
Entry.objects.filter(pub_date__month__gte=6)

Équivalence en SQL :

SELECT ... WHERE EXTRACT('month' FROM pub_date) = '12';
SELECT ... WHERE EXTRACT('month' FROM pub_date) >= '6';

(La syntaxe SQL exacte varie d’un moteur de base de données à l’autre.)

Lorsque USE_TZ vaut True, les champs date/heure sont convertis dans le fuseau horaire en cours avant le filtrage. Cela nécessite la présence des définitions de fuseaux horaires dans la base de données.

Changed in Django 1.9:

Possibilité de faire suivre l’expression par d’autres expressions de champs.

day

Pour les champs date et date/heure, une correspondance exacte du jour. Cette expression peut être suivie d’autres expressions de champs. Accepte un jour comme nombre entier.

Exemple :

Entry.objects.filter(pub_date__day=3)
Entry.objects.filter(pub_date__day__gte=3)

Équivalence en SQL :

SELECT ... WHERE EXTRACT('day' FROM pub_date) = '3';
SELECT ... WHERE EXTRACT('day' FROM pub_date) >= '3';

(La syntaxe SQL exacte varie d’un moteur de base de données à l’autre.)

Notez que cela correspond à tout élément dont le champ pub_date est égal au troisième jour du mois, comme le 3 janvier, le 3 juillet, etc.

Lorsque USE_TZ vaut True, les champs date/heure sont convertis dans le fuseau horaire en cours avant le filtrage. Cela nécessite la présence des définitions de fuseaux horaires dans la base de données.

Changed in Django 1.9:

Possibilité de faire suivre l’expression par d’autres expressions de champs.

week_day

Pour les champs date et date/heure, une correspondance exacte du « jour de la semaine ». Cette expression peut être suivie d’autres expressions de champs.

Accepte un nombre entier représentant le jour de la semaine, de 1 (dimanche) à 7 (samedi).

Exemple :

Entry.objects.filter(pub_date__week_day=2)
Entry.objects.filter(pub_date__week_day__gte=2)

(Nous n’avons pas inclus de code SQL équivalent pour cette recherche car l’implémentation de la requête correspondante varie beaucoup selon le moteur de base de données.)

Notez que cela correspond à tout élément dont le champ pub_date est un lundi (jour 2 de la semaine), sans tenir compte du mois ou de l’année. Les jours de la semaine sont indexés de 1 (dimanche) à 7 (samedi).

Lorsque USE_TZ vaut True, les champs date/heure sont convertis dans le fuseau horaire en cours avant le filtrage. Cela nécessite la présence des définitions de fuseaux horaires dans la base de données.

Changed in Django 1.9:

Possibilité de faire suivre l’expression par d’autres expressions de champs.

hour

Pour les champs date/heure et heure, une correspondance exacte de l’heure. Cette expression peut être suivie d’autres expressions de champs. Accepte un nombre entier entre 0 et 23.

Exemple :

Event.objects.filter(timestamp__hour=23)
Event.objects.filter(time__hour=5)
Event.objects.filter(timestamp__hour__gte=12)

Équivalence en SQL :

SELECT ... WHERE EXTRACT('hour' FROM timestamp) = '23';
SELECT ... WHERE EXTRACT('hour' FROM time) = '5';
SELECT ... WHERE EXTRACT('hour' FROM timestamp) >= '12';

(La syntaxe SQL exacte varie d’un moteur de base de données à l’autre.)

Pour les champs date/heure, lorsque USE_TZ vaut True, les valeurs sont converties dans le fuseau horaire en cours avant le filtrage.

Changed in Django 1.9:

La prise en charge de TimeField avec SQLite (les autres bases de données l’acceptaient depuis 1.7) a été ajoutée.

Changed in Django 1.9:

Possibilité de faire suivre l’expression par d’autres expressions de champs.

minute

Pour les champs date/heure et heure, une correspondance exacte de la minute. Cette expression peut être suivie d’autres expressions de champs. Accepte un nombre entier entre 0 et 59.

Exemple :

Event.objects.filter(timestamp__minute=29)
Event.objects.filter(time__minute=46)
Event.objects.filter(timestamp__minute__gte=29)

Équivalence en SQL :

SELECT ... WHERE EXTRACT('minute' FROM timestamp) = '29';
SELECT ... WHERE EXTRACT('minute' FROM time) = '46';
SELECT ... WHERE EXTRACT('minute' FROM timestamp) >= '29';

(La syntaxe SQL exacte varie d’un moteur de base de données à l’autre.)

Pour les champs date/heure, lorsque USE_TZ vaut True, les valeurs sont converties dans le fuseau horaire en cours avant le filtrage.

Changed in Django 1.9:

La prise en charge de TimeField avec SQLite (les autres bases de données l’acceptaient depuis 1.7) a été ajoutée.

Changed in Django 1.9:

Possibilité de faire suivre l’expression par d’autres expressions de champs.

second

Pour les champs date/heure et heure, une correspondance exacte de la seconde. Cette expression peut être suivie d’autres expressions de champs. Accepte un nombre entier entre 0 et 59.

Exemple :

Event.objects.filter(timestamp__second=31)
Event.objects.filter(time__second=2)
Event.objects.filter(timestamp__second__gte=31)

Équivalence en SQL :

SELECT ... WHERE EXTRACT('second' FROM timestamp) = '31';
SELECT ... WHERE EXTRACT('second' FROM time) = '2';
SELECT ... WHERE EXTRACT('second' FROM timestamp) >= '31';

(La syntaxe SQL exacte varie d’un moteur de base de données à l’autre.)

Pour les champs date/heure, lorsque USE_TZ vaut True, les valeurs sont converties dans le fuseau horaire en cours avant le filtrage.

Changed in Django 1.9:

La prise en charge de TimeField avec SQLite (les autres bases de données l’acceptaient depuis 1.7) a été ajoutée.

Changed in Django 1.9:

Possibilité de faire suivre l’expression par d’autres expressions de champs.

isnull

Accepte True ou False, ce qui correspond respectivement aux instructions SQL IS NULL et IS NOT NULL.

Exemple :

Entry.objects.filter(pub_date__isnull=True)

Équivalence en SQL :

SELECT ... WHERE pub_date IS NULL;

regex

Recherche par expression régulière, sensible à la casse.

La syntaxe d’expression régulière est celle du moteur de base de données utilisé. Pour SQLite qui ne prend pas en charge nativement les expressions régulières, cette fonctionnalité est fournie par une fonction (Python) REGEXP définie par l’utilisateur, et la syntaxe d’expression régulière est par conséquent celle du module re de Python.

Exemple :

Entry.objects.get(title__regex=r'^(An?|The) +')

Équivalence en SQL :

SELECT ... WHERE title REGEXP BINARY '^(An?|The) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(An?|The) +', 'c'); -- Oracle

SELECT ... WHERE title ~ '^(An?|The) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '^(An?|The) +'; -- SQLite

Il est recommandé d’utiliser des chaînes brutes (par ex. r'foo' au lieu de 'foo') pour transmettre des expressions régulières.

iregex

Recherche par expression régulière, insensible à la casse.

Exemple :

Entry.objects.get(title__iregex=r'^(an?|the) +')

Équivalence en SQL :

SELECT ... WHERE title REGEXP '^(an?|the) +'; -- MySQL

SELECT ... WHERE REGEXP_LIKE(title, '^(an?|the) +', 'i'); -- Oracle

SELECT ... WHERE title ~* '^(an?|the) +'; -- PostgreSQL

SELECT ... WHERE title REGEXP '(?i)^(an?|the) +'; -- SQLite

Fonctions d’agrégation

Django fournit les fonctions d’agrégation suivantes dans le module django.db.models. Pour plus de détails sur l’usage de ces fonctions, consultez le guide thématique sur l’agrégation. Consultez la documentation de Aggregate pour apprendre à créer vos propres agrégations.

Avertissement

SQLite ne sait pas nativement gérer des agrégations sur des champs date/heure. La raison est qu’il n’existe pas de vrais champs date/heure dans SQLite et que Django émule actuellement ces fonctions en utilisant un champ texte. Si vous essayez d’effectuer des agrégations sur des champs date/heure avec SQLite, vous obtiendrez l’exception NotImplementedError.

Note

Les fonctions d’agrégation renvoient None lorsqu’elles sont utilisées avec un objet QuerySet vide. Par exemple, la fonction d’agrégation Sum (somme) renvoie None au lieu de 0 si le jeu de requête ne contient pas d’élément. Une exception est Count, qui renvoie 0 quand le jeu de requête est vide.

Toutes les agrégations partagent les paramètres suivants :

expression

Une chaîne référençant un champ du modèle, ou une expression de requête.

output_field

Un paramètre facultatif représentant le champ de modèle de la valeur renvoyée.

Note

Lors de la combinaison de plusieurs types de champs, Django ne peut déterminer le type de résultat output_field qui si tous les champs sont du même type. Sinon, vous devez indiquer output_field vous-même.

**extra

Paramètres nommés qui peuvent fournir du contexte supplémentaire pour le code SQL généré par l’agrégation.

Avg

class Avg(expression, output_field=FloatField(), **extra)[source]

Renvoie la valeur moyenne de l’expression indiquée, qui doit être de type numérique, sauf si vous indiquez un champ output_field différent.

  • Alias par défaut : <champ>__avg

  • Type renvoyé : float (ou le type d’un éventuel champ output_field fourni)

Changed in Django 1.9:

Le paramètre output_field a été ajouté pour permettre l’agrégation sur des colonnes non numériques, comme par exemple DurationField.

Count

class Count(expression, distinct=False, **extra)[source]

Renvoie le nombre d’objets liés au travers de l’expression indiquée.

  • Alias par défaut : <champ>__count

  • Type de la valeur renvoyée : int

Accepte un paramètre facultatif :

distinct

Si distinct=True, le dénombrement ne tient compte que des instances uniques. Cela correspond au code SQL COUNT(DISTINCT <field>). La valeur par défaut est False`.

Max

class Max(expression, output_field=None, **extra)[source]

Renvoie la valeur maximale de l’expression donnée.

  • Alias par défaut : <champ>__max

  • Type de la valeur renvoyée : identique au champ de départ, ou output_field s’il est indiqué

Min

class Min(expression, output_field=None, **extra)[source]

Renvoie la valeur minimale de l’expression donnée.

  • Alias par défaut : <champ>__min

  • Type de la valeur renvoyée : identique au champ de départ, ou output_field s’il est indiqué

StdDev

class StdDev(expression, sample=False, **extra)[source]

Renvoie la déviation standard des données contenues dans l’expression donnée.

  • Alias par défaut : <champ>__stddev

  • Type de la valeur renvoyée : float

Accepte un paramètre facultatif :

sample

Par défaut, StdDev renvoie la déviation standard de population. Cependant, si sample=True, la valeur renvoyée sera la déviation standard d’échantillon.

SQLite

SQLite ne fournit pas la fonction StdDev dans sa version de base. Une implémentation est disponible sous forme de module d’extension pour SQLite. Consultez la documentation de SQLite pour des instructions sur l’obtention et l’installation de cette extension.

Sum

class Sum(expression, output_field=None, **extra)[source]

Calcule la somme de toutes les valeurs de l’expression donnée.

  • Alias par défaut : <champ>__sum

  • Type de la valeur renvoyée : identique au champ de départ, ou output_field s’il est indiqué

Variance

class Variance(expression, sample=False, **extra)[source]

Renvoie la variance des données de l’expression donnée.

  • Alias par défaut : <champ>__variance

  • Type de la valeur renvoyée : float

Accepte un paramètre facultatif :

sample

Par défaut, Variance renvoie la variance de population. Cependant, si sample=True, la valeur renvoyée sera la variance d’échantillon.

SQLite

SQLite ne fournit pas la fonction Variance dans sa version de base. Une implémentation est disponible sous forme de module d’extension pour SQLite. Consultez la documentation de SQLite pour des instructions sur l’obtention et l’installation de cette extension.

Back to Top