# Documentation Django 3.1.9.dev

# Création de requêtes

Une fois les modèles de données créés, Django offre automatiquement une API d’abstraction de base de données qui permet de créer, obtenir, mettre à jour et supprimer des objets. Ce document explique comment utiliser cette API. Consultez la référence des modèles de données pour des détails complets sur toutes les options d’interrogation des modèles.

À travers ce guide (et dans la référence), nous nous référons aux modèles suivants, qui forment une application de blog :

    from django.db import models

    class Blog(models.Model):
        name = models.CharField(max_length=100)
        tagline = models.TextField()

        def __str__(self):
            return self.name

    class Author(models.Model):
        name = models.CharField(max_length=200)
        email = models.EmailField()

        def __str__(self):
            return self.name

    class Entry(models.Model):
        blog = models.ForeignKey(Blog, on_delete=models.CASCADE)
        headline = models.CharField(max_length=255)
        body_text = models.TextField()
        pub_date = models.DateField()
        mod_date = models.DateField()
        authors = models.ManyToManyField(Author)
        number_of_comments = models.IntegerField()
        number_of_pingbacks = models.IntegerField()
        rating = models.IntegerField()

        def __str__(self):
            return self.headline

## Création d’objets

Pour représenter des données d’une table de base de données en objets Python, Django utilise un système intuitif : une classe de modèle représente une table de base de données, et une instance de cette classe représente un enregistrement particulier dans la table de base de données.

Pour créer un objet, créez une instance de la classe de modèle en utilisant des paramètres nommés, puis appelez `save()` pour l’enregistrer dans la base de données.

En supposant que les modèles se trouvent dans un fichier `mysite/blog/models.py`, voici un exemple :

    >>> from blog.models import Blog
    >>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
    >>> b.save()

Ceci exécute une commande SQL `INSERT` en arrière-plan. Django ne sollicite pas la base de données tant que vous n’appelez pas explicitement `save()`.

La méthode `save()` ne renvoie aucune valeur.

Voir aussi

`save()` accepte un certain nombre d’options avancées décrites ailleurs. Consultez la documentation de `save()` pour les détails complets.

Pour créer et enregistrer un objet en une seule étape, utilisez la méthode `create()`.

## Enregistrement des modifications d’objets

Pour enregistrer les modifications d’un objet existant dans la base de données, utilisez `save()`.

Considérant une instance `b5` d’un `Blog` ayant déjà été enregistrée dans la base de données, cet exemple modifie son nom et met à jour son enregistrement dans la base de données :

    >>> b5.name = 'New name'
    >>> b5.save()

Ceci génère une commande SQL `UPDATE` en arrière-plan. Django ne sollicite pas la base de données tant que vous n’appelez pas explicitement `save()`.

### Enregistrement des champs `ForeignKey` et `ManyToManyField`

La mise à jour d’un champ `ForeignKey` fonctionne exactement de la même façon que l’enregistrement d’un champ normal, attribuez un objet du bon type au champ en question. Cet exemple met à jour l’attribut `blog` d’une instance `Entry` nommée `entry`, en supposant que les instances appropriées de `Entry` et de `Blog` sont déjà enregistrées dans la base de données (afin de pouvoir être récupérées ci-dessous) :

    >>> from blog.models import Blog, Entry
    >>> entry = Entry.objects.get(pk=1)
    >>> cheese_blog = Blog.objects.get(name="Cheddar Talk")
    >>> entry.blog = cheese_blog
    >>> entry.save()

La mise à jour d’un champ `ManyToManyField` fonctionne un peu différemment ; utilisez la méthode `add()` du champ pour ajouter un enregistrement à la relation. Cet exemple ajoute l’instance `Author` `joe` à l’objet `entry`:

    >>> from blog.models import Author
    >>> joe = Author.objects.create(name="Joe")
    >>> entry.authors.add(joe)

Pour ajouter plusieurs enregistrements à un champ `ManyToManyField` d’un seul coup, indiquez plusieurs paramètres dans l’appel à `add()`, comme ceci :

    >>> john = Author.objects.create(name="John")
    >>> paul = Author.objects.create(name="Paul")
    >>> george = Author.objects.create(name="George")
    >>> ringo = Author.objects.create(name="Ringo")
    >>> entry.authors.add(john, paul, george, ringo)

Django se plaint si vous essayez d’assigner ou d’ajouter un objet de type inapproprié.

## Sélection d’objets

Pour extraire des objets de la base de données, construisez un `QuerySet` via un `Manager` de la classe de votre modèle.

Un `QuerySet` représente une collection d’objets de la base de données. Il peut comporter zéro, un ou plusieurs filtres. Les filtres réduisent les résultats de requêtes en fonction des paramètres donnés. En termes SQL, un `QuerySet` équivaut à une commande `SELECT` et un filtre correspond à une clause restrictive telle que `WHERE` ou `LIMIT`.

On obtient un `QuerySet` en utilisant le `Manager` du modèle. Chaque modèle a au moins un `Manager` ; il s’appelle `objects` par défaut. On y accède directement via la classe du modèle, comme ceci :

    >>> Blog.objects
    <django.db.models.manager.Manager object at ...>
    >>> b = Blog(name='Foo', tagline='Bar')
    >>> b.objects
    Traceback:
        ...
    AttributeError: "Manager isn't accessible via Blog instances."

Note

Les `Managers` ne sont accessibles que par les classes de modèle et non par les instances de modèle, afin d’accentuer la séparation entre les opérations sur les « tables » et les opérations sur les « enregistrements ».

Le `Manager` est la source principale des `QuerySets` d’un modèle. Par exemple, `Blog.objects.all()` renvoie un `QuerySet` contenant tous les objets `Blog` de la base de données.

### Sélection de tous les objets

La façon la plus simple d’obtenir des objets d’une table est de tous les sélectionner. Pour ce faire, utilisez la méthode `all()` d’un `Manager`:

    >>> all_entries = Entry.objects.all()

La méthode `all()` renvoie un `QuerySet` de tous les objets dans la base de données.

### Sélection d’objets spécifiques avec les filtres

Le `QuerySet` renvoyé par `all()` contient tous les objets de la table de la base de données. Mais le plus souvent, seul un sous-ensemble de tous les objets devra être sélectionné.

Pour créer un tel sous-ensemble, vous affinez le `QuerySet` initial en y ajoutant des filtres de conditions. Les deux façons les plus utilisées pour affiner un `QuerySet` sont :

`filter(**kwargs)`
  Renvoie un nouveau `QuerySet` contenant les objets qui répondent aux paramètres de recherche donnés.
`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` dans les définitions de fonction ci-dessus) doivent être dans le format décrit dans Recherches dans les champs ci-dessous.

Par exemple, pour obtenir un `QuerySet` des articles de blog de l’année 2006, utilisez `filter()` comme ceci :

    Entry.objects.filter(pub_date__year=2006)

Avec la classe de gestionnaire par défaut, c’est équivalent à :

    Entry.objects.all().filter(pub_date__year=2006)

#### Enchaînement des filtres

Le résultat de l’affinage d’un `QuerySet` est lui-même un `QuerySet`, il est donc possible d’enchaîner les filtrages successifs. Par exemple :

    >>> Entry.objects.filter(
    ...     headline__startswith='What'
    ... ).exclude(
    ...     pub_date__gte=datetime.date.today()
    ... ).filter(
    ...     pub_date__gte=datetime.date(2005, 1, 30)
    ... )

À partir du `QuerySet` initial de toutes les lignes dans la base de données, le code ci-dessus ajoute un filtre, puis une exclusion, puis un autre filtre. Le résultat final est un `QuerySet` contenant tous les enregistrements ayant un titre (`headline`) commençant par « What », ayant été publiés entre le 30 janvier 2005 et aujourd’hui.

#### Les `QuerySet` filtrés sont uniques

À chaque fois que vous affinez un `QuerySet`, vous obtenez un `QuerySet` tout neuf qui n’est lié d’aucune manière au `QuerySet` précédent. Chaque affinage crée un `QuerySet` séparé et distinct qui peut être stocké, utilisé et réutilisé.

Exemple :

    >>> q1 = Entry.objects.filter(headline__startswith="What")
    >>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
    >>> q3 = q1.filter(pub_date__gte=datetime.date.today())

Ces trois `QuerySet` sont séparés. Le premier est un `QuerySet` de base contenant tous les enregistrements qui contiennent un titre commençant par « What ». Le second est un sous-ensemble du premier, avec un critère supplémentaire qui exclut les enregistrements dont le champ `pub_date` est aujourd’hui ou dans le futur. Le troisième est un sous-ensemble du premier, avec un critère supplémentaire qui sélectionne uniquement les enregistrements dont le champ `pub_date` est aujourd’hui ou dans le futur. Le `QuerySet` initial (`q1`) n’est pas affecté par le processus d’affinage.

#### Les objects `QuerySet` sont différés

Les `QuerySets` sont différés (« lazy ») ; la création d’un `QuerySet` ne génère aucune activité au niveau de la base de données. Vous pouvez empiler les filtres toute la journée, Django ne lance aucune requête tant que le `QuerySet` n’est pas évalué. Regardez cet exemple :

    >>> q = Entry.objects.filter(headline__startswith="What")
    >>> q = q.filter(pub_date__lte=datetime.date.today())
    >>> q = q.exclude(body_text__icontains="food")
    >>> print(q)

Malgré le fait que ceci ressemble à trois interrogations de la base de données, en réalité une seule interrogation est faite, à la dernière ligne (`print(q)`). En général, les résultats d’un `QuerySet` ne sont récupérés de la base de données que lorsque vous les « demandez ». Lorsque cela arrive, le `QuerySet` est évalué en accédant à la base de données. Pour plus de détails sur le moment exact où l’évaluation a lieu, consultez Quand les objets QuerySet sont évalués.

### Sélection d’un objet unique avec `get()`

`filter()` renvoie toujours un `QuerySet`, même si la requête ne renvoie qu’un seul objet ; dans ce cas, le `QuerySet` ne contiendra simplement qu’un seul élément.

Si vous savez qu’un seul objet correspondra à votre requête, vous pouvez utiliser la méthode `get()` d’un `Manager` qui renvoie directement l’objet :

    >>> one_entry = Entry.objects.get(pk=1)

N’importe quelle expression de recherche peut être utilisée avec `get()`, comme pour `filter()`. Voir Recherches dans les champs ci-dessous.

Notez qu’il y a une différence entre l’utilisation de `get()` et celle de `filter()` avec le segment `[0]`. Si aucun résultat ne correspond à la requête, `get()` génère une exception `DoesNotExist`. Cette exception est un attribut de la classe de modèle sur laquelle la requête est appliquée ; ainsi, dans le code ci-dessus, s’il n’existe pas d’objet `Entry` avec une clé primaire de 1, Django génère l’exception `Entry.DoesNotExist`.

De même, Django réagit si plus d’un élément correspond à la requête `get()`. Dans ce cas, il lève l’exception `MultipleObjectsReturned` qui est également un attribut de la classe de modèle elle-même.

### Autres méthodes de `QuerySet`

La plupart du temps, vous utiliserez `all()`, `get()`, `filter()` et `exclude()` lorsque vous aurez besoin de sélectionner des objets dans la base de données. Cependant, c’est loin d’être tout ; consultez la référence de l’API QuerySet pour une liste complète des diverses méthodes de `QuerySet`.

### Limitation des `QuerySet`

Utilisez un sous-ensemble de la syntaxe Python de segmentation des listes pour restreindre un `QuerySet` à un certain nombre de résultats. C’est l’équivalent des clauses SQL `LIMIT` et `OFFSET`.

Par exemple, ceci renvoie les 5 premiers objets (`LIMIT 5`) :

    >>> Entry.objects.all()[:5]

Ceci renvoie du sixième au dixième objet (`OFFSET 5 LIMIT 5`) :

    >>> Entry.objects.all()[5:10]

Les index négatifs (ex. : `Entry.objects.all()[-1]`) ne sont pas pris en charge.

De manière générale, la segmentation d’un `QuerySet` renvoie un nouveau `QuerySet` ; la requête n’est pas évaluée, sauf si vous utilisez le paramètre `step` de la syntaxe de segmentation de Python. Par exemple, ceci exécuterait effectivement la requête pour renvoyer une liste d’un objet sur 2 parmi les 10 premiers :

    >>> Entry.objects.all()[:10:2]

Tout filtre ou tri subséquent d’un jeu de requête segmenté est interdit en raison de la nature ambiguë de son éventuel fonctionnement.

Pour obtenir un seul objet plutôt qu’une liste (ex. : `SELECT foo FROM bar LIMIT 1`), utilisez un index au lieu d’un segment. Par exemple, ceci renvoie le premier objet `Entry` de la base de données, après avoir trié les objets alphabétiquement par titre (`headline`) :

    >>> Entry.objects.order_by('headline')[0]

C’est grossièrement équivalent à :

    >>> Entry.objects.order_by('headline')[0:1].get()

Notez toutefois que si aucun objet ne correspond à la requête, une exception `IndexError` est générée dans le premier cas, tandis que dans le second cas, c’est l’exception `DoesNotExist` qui sera générée. Voir `get()` 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`.

Les paramètres nommés de base de ces requêtes prennent la forme `champ__typerequete=valeur` (il s’agit d’un double soulignement). Par exemple :

    >>> Entry.objects.filter(pub_date__lte='2006-01-01')

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

    SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01';

Comment est-ce possible ?

Python permet de définir des fonctions acceptant des paramètres nom-valeur arbitraires dont les noms et les valeurs sont évalués au moment de l’exécution. Pour plus d’informations, consultez Keyword Arguments dans le tutoriel Python officiel.

Le champ indiqué dans une recherche doit correspondre au nom d’un champ de modèle. Il existe cependant une exception ; dans le cas d’une clé étrangère `ForeignKey`, vous pouvez indiquer le nom du champ additionné du suffixe `_id`. Dans ce cas, le paramètre valeur doit contenir la valeur brute de la clé primaire du modèle étranger. Par exemple :

    >>> Entry.objects.filter(blog_id=4)

Si vous fournissez un paramètre nommé non valide, une fonction de recherche signalera une exception `TypeError`.

L’API de base de données gère une vingtaine de types de recherche ; une référence complète se trouve dans la référence des recherches de champs. Pour vous donner une idée de ce qui est possible, voici quelques recherches parmi les plus fréquemment utilisées :

`exact`

  Une correspondance « exacte ». Par exemple :

      >>> Entry.objects.get(headline__exact="Cat bites dog")

  Produit le code SQL ressemblant à :

      SELECT ... WHERE headline = 'Cat bites dog';

  Si vous n’indiquez pas de type de recherche, c’est-à-dire si votre paramètre nommé ne contient pas de double soulignement, Django considère que le type de recherche est `exact`.

  Par exemple, les deux lignes suivantes sont équivalentes :

      >>> Blog.objects.get(id__exact=14)  # Explicit form
      >>> Blog.objects.get(id=14)         # __exact is implied

  Il s’agit d’un raccourci commode, puisque les recherches `exact` sont les cas les plus courants.

`iexact`

  Une recherche insensible à la casse. Ainsi, la requête :

      >>> Blog.objects.get(name__iexact="beatles blog")

  Aurait pour occurrence un `Blog` intitulé `"Beatles Blog"`, `"beatles blog"` ou même `"BeAtlES blOG"`.

`contains`

  Test d’inclusion sensible à la casse. Par exemple :

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

  Pourrait être traduit grosso modo par ce code SQL :

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

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

  Il existe aussi une version insensible à la casse, `icontains`.

`startswith`, `endswith`
  Recherche « commençant par » et « finissant par », respectivement. Il en existe aussi des versions insensibles à la casse : `istartswith` et `iendswith`.

Encore une fois, ce n’est qu’un survol. Une référence complète est disponible dans la référence des recherches de champ.

### Recherches traversant les relations

Django offre une approche puissante et intuitive pour « suivre » les relations dans les recherches, se chargeant automatiquement des `JOIN` SQL en arrière-plan. Pour atteindre une relation, utilisez les noms de champ qui servent de relation vers d’autres modèles, séparés par des doubles soulignements, jusqu’à atteindre le champ souhaité.

Cet exemple sélectionne tous les objets `Entry` d’un `Blog` ayant pour `name` la valeur `'Beatles Blog'`:

    >>> Entry.objects.filter(blog__name='Beatles Blog')

Ce mécanisme de traversée de relations peut être aussi profond que vous le souhaitez.

Ceci fonctionne également dans le sens inverse. Même s’il `peut être personnalisé`, la manière par défaut de se référer à une relation « inverse » dans une expression de requête est d’utiliser le nom du modèle en minuscules.

Cet exemple sélectionne tous les objets `Blog` ayant au moins une `Entry` ayant un `headline` contenant `'Lennon'`:

    >>> Blog.objects.filter(entry__headline__contains='Lennon')

Si vous filtrez à travers plusieurs relations et qu’un des modèles intermédiaires n’a pas de valeur répondant à la condition du filtre, Django le traite comme s’il y avait là un objet vide (toutes les valeurs sont `NULL`), mais valide. C’est-à-dire qu’aucune erreur ne sera signalée. Par exemple, dans ce filtre :

    Blog.objects.filter(entry__authors__name='Lennon')

(partant du principe qu’il existe un modèle `Author` lié), s’il n’y a pas de `author` associé à une `entry`, ce sera traité comme s’il n’y avait pas non plus de `name`, plutôt que de signaler une erreur à cause de l”`author` manquant. Normalement, c’est bien le comportement souhaité. Le seul cas où ça pourrait porter à confusion, c’est quand vous utilisez `isnull`. Ainsi :

    Blog.objects.filter(entry__authors__name__isnull=True)

renvoie les objets `Blog` ayant un `author` avec le `name` vide ainsi que tous ceux ayant un `author` vide dans l”`entry`. Si vous ne voulez pas de cette deuxième catégorie d’objets, vous pourriez écrire :

    Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True)

#### Traversée des relations multivaluées

Quand vous filtrez un objet basé sur un champ `ManyToManyField` ou un champ `ForeignKey` inversé, deux types de filtres peuvent être intéressants. Considérez la relation `Blog`/`Entry` (`Blog` vers `Entry` est une relation un-à-plusieurs). Nous pourrions être intéressés à trouver des blogues qui ont une entrée contenant « Lennon » dans le titre et ayant été publiée en 2008. Ou nous pourrions vouloir trouver des blogues qui contiennent une entrée avec « Lennon » dans le titre et une entrée qui a été publiée en 2008. Comme il y a plusieurs entrées associées à un seul `Blog`, ces deux requêtes sont possibles et ont du sens dans certaines situations.

Le même genre de situation survient avec un champ `ManyToManyField`. Par exemple, si une `Entry` avait un `ManyToManyField` nommé `tags`, nous pourrions vouloir trouver des entrées liées aux `tags` nommés « music » et « bands », ou nous pourrions vouloir une entrée qui contient un `tag` avec le nom « music » et un statut « public ».

Pour gérer ces deux situations, Django a une façon cohérente de traiter les appels de `filter()`. Tous les paramètres d’un appel à `filter()` sont appliqués simultanément pour filtrer les éléments qui correspondent à tous ces critères. Les appels subséquents à `filter()` restreignent ensuite davantage les éléments renvoyés, mais pour les relations multivaluées ces appels s’appliquent à tous les objets liés au modèle principal, pas nécessairement aux objets (dépendants du modèle principal) qui ont été sélectionnés par un appel précédent à `filter()`.

Ceci peut paraître un peu déroutant ; nous espérons qu’un exemple viendra clarifier les choses. Pour sélectionner tous les blogues qui contiennent des entrées qui ont à la fois « Lennon » dans le titre et qui ont été publiées en 2008 (la même entrée qui satisfait les deux conditions), nous pourrions écrire :

    Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008)

Pour sélectionner tous les blogues qui contiennent une entrée avec « Lennon » dans le titre et d’autre part une entrée qui a été publiée en 2008, nous pourrions écrire :

    Blog.objects.filter(entry__headline__contains='Lennon').filter(entry__pub_date__year=2008)

En supposant qu’un seul blogue contienne à la fois des articles contenant « Lennon » et des articles de 2008, mais qu’aucun des articles de 2008 ne contient « Lennon », la première requête ne renverrait aucun blogue alors que la seconde requête renverrait ce blogue.

Dans le deuxième exemple, le premier filtre restreint le queryset à tous les blogues avec un lien vers des articles contentant « Lennon » dans le titre. Le second filtre restreint davantage les blogues résultants à ceux qui ont aussi un lien vers les articles publiés en 2008. Les articles sélectionnés par le second filtre peuvent être ou non les mêmes que ceux sélectionnés par le premier filtre. Nous filtrons les éléments `Blog` avec chaque appel de filtre, pas les éléments `Entry`.

Note

Le comportement de `filter()` pour les requêtes qui couvrent des relations multi-valeurs” tel que décrit ci-dessus, n’est pas implémenté de la même manière pour `exclude()`. Au contraire, les conditions de restriction indiquées lors qu’un appel à `exclude()` ne doivent pas nécessairement s’appliquer au même élément.

Par exemple, la requête ci-dessous exclurait les blogues qui contiennent à la fois « Lennon » dans le titre et des entrées publiées en 2008

    Blog.objects.exclude(
        entry__headline__contains='Lennon',
        entry__pub_date__year=2008,
    )

Cependant, contrairement au comportement lors de l’utilisation de `filter()`, cela ne sélectionnera pas les blogs basés sur des entrées qui satisfont les deux conditions en même temps. Pour faire cela, c’est à dire pour sélectionner tous les blogs qui ne contiennent pas d’entrées publiées avec « Lennon » et qui ont été publiées en 2008, vous devez faire deux requêtes

    Blog.objects.exclude(
        entry__in=Entry.objects.filter(
            headline__contains='Lennon',
            pub_date__year=2008,
        ),
    )

### Les filtres peuvent référencer les champs d’un modèle

Dans les exemples donnés jusqu’ici, nous avons construit des filtres comparant la valeur d’un champ de modèle avec une constante. Mais qu’en est-il si vous souhaitez comparer la valeur d’un champ de modèle avec un autre champ du même modèle ?

Django propose les `expressions F` pour autoriser de telles comparaisons. Les instances de `F()` agissent comme des références vers un champ de modèle à l’intérieur d’une requête. Ces références peuvent ensuite être utilisées dans des filtres de requêtes pour comparer les valeurs de deux champs différents d’une même instance de modèle.

Par exemple, pour obtenir la liste de tous les articles de blogue ayant reçus plus de commentaires que de « pings », nous construisons un objet `F()` pour référencer le nombre de pings afin d’utiliser cet objet `F()` dans la requête :

    >>> from django.db.models import F
    >>> Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks'))

Django prend en charge l’utilisation des opérateurs arithmétiques addition, soustraction, multiplication, division, modulo et puissance avec les objets `F()`, aussi bien avec des constantes qu’avec d’autres objets `F()`. Pour obtenir tous les articles de blogue avec plus de deux fois de commentaires que de pings, nous modifions ainsi la requête :

    >>> Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks') * 2)

Pour trouver tous les articles où la notation de l’article est plus petite que la somme des pings et des commentaires, nous pourrions effectuer cette requête :

    >>> Entry.objects.filter(rating__lt=F('number_of_comments') + F('number_of_pingbacks'))

Vous pouvez aussi employer la notation en double soulignement pour traverser les relations dans un objet `F()`. Un objet `F()` contenant un double soulignement produira toute jointure nécessaire pour accéder aux objets liés. Par exemple, pour obtenir tous les articles dont le nom de l’auteur est égal au nom du blogue, nous pourrions effectuer la requête :

    >>> Entry.objects.filter(authors__name=F('blog__name'))

Pour les champs date et date/heure, il est possible d’ajouter ou de soustraire un objet `timedelta`. L’exemple suivant renvoie tous les articles modifiés plus de 3 jours après avoir été publiés :

    >>> from datetime import timedelta
    >>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))

Les objets `F()` prennent en charge les opérations bit à bit via `.bitand()`, `.bitor()`, `.bitxor()`, `.bitrightshift()` et `.bitleftshift()`. Par exemple :

    >>> F('somefield').bitand(16)

Oracle

Oracle ne prend pas en charge l’opération bit à bit XOR.

Changed in Django 3.1:

La prise en charge de `.bitxor()` a été ajoutée.

### Le raccourci de recherche `pk`

Pour des raisons pratiques, Django fournit un raccourci de recherche `pk`, signifiant « primary key » (clé primaire).

Dans le modèle d’exemple `Blog`, la clé primaire est le champ `id`. Ainsi, ces trois lignes sont équivalentes :

    >>> Blog.objects.get(id__exact=14) # Explicit form
    >>> Blog.objects.get(id=14) # __exact is implied
    >>> Blog.objects.get(pk=14) # pk implies id__exact

L’emploi de `pk` n’est pas limité aux requêtes `__exact`; toute expression de requête peut être combinée avec `pk` pour effectuer une requête sur la clé primaire d’un modèle :

    # Get blogs entries with id 1, 4 and 7
    >>> Blog.objects.filter(pk__in=[1,4,7])

    # Get all blog entries with id > 14
    >>> Blog.objects.filter(pk__gt=14)

Les recherches sur `pk` fonctionnent également en traversant les relations. Par exemple, ces trois lignes sont équivalentes :

    >>> Entry.objects.filter(blog__id__exact=3) # Explicit form
    >>> Entry.objects.filter(blog__id=3)        # __exact is implied
    >>> Entry.objects.filter(blog__pk=3)        # __pk implies __id__exact

### Échappement des signes pour cent et des soulignements dans les instructions `LIKE`

Les recherches de champs produisant des instructions SQL `LIKE` (`iexact`, `contains`, `icontains`, `startswith`, `istartswith`, `endswith` et `iendswith`) échappent automatiquement les deux caractères à signification spéciale des instructions `LIKE`: le signe pour cent et le soulignement (dans une instruction `LIKE`, le signe pour cent est utilisé comme caractère de remplacement multiple alors qu’un soulignement est utilisé comme caractère de remplacement unique).

Cela signifie que les choses devraient fonctionner intuitivement, sans faille d’abstraction. Par exemple, pour obtenir la liste de tous les articles contenant un signe pour cent, indiquez le signe pour cent comme pour n’importe quel autre caractère :

    >>> Entry.objects.filter(headline__contains='%')

Django se charge de l’échappement à votre place ; le code SQL résultant ressemblera à quelque chose comme :

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

Même chose pour les soulignements. Aussi bien les signes pour cent que les soulignements sont gérés pour vous de manière transparente.

### Mise en cache et objets `QuerySet`

Chaque `QuerySet` contient un cache pour minimiser l’accès à la base de données. La compréhension de son fonctionnement vous permet d’écrire le code le plus efficace possible.

Pour un nouvel objet `QuerySet`, son cache est vide. À la première évaluation d’un `QuerySet` (et donc qu’une requête de base de données est effectuée), Django enregistre les résultats de la requête dans le cache de l’objet `QuerySet` et renvoie les résultats qui ont été explicitement demandés (par ex. l’élément suivant dans le cas d’une itération du `QuerySet`). Les évaluations suivantes de l’objet `QuerySet` réutilisent les résultats mis en cache.

Gardez à l’esprit ce comportement de mise en cache, car vous pourriez vous faire avoir si vous n’utilisez pas correctement l’objet `QuerySet`. Par exemple, le code suivant crée deux objets `QuerySet`, les évalue et les abandonne :

    >>> print([e.headline for e in Entry.objects.all()])
    >>> print([e.pub_date for e in Entry.objects.all()])

Dans ce cas, la même requête de base de données est exécutée deux fois, ce qui double en pratique la charge sur la base de données. Il est également imaginable que les deux listes ne contiennent pas exactement les mêmes enregistrements de base de données, car un objet `Entry` pourrait avoir été ajouté ou supprimé dans la fraction de seconde entre les deux requêtes.

Pour éviter ce problème, stockez l’objet `QuerySet` et réutilisez-le :

    >>> queryset = Entry.objects.all()
    >>> print([p.headline for p in queryset]) # Evaluate the query set.
    >>> print([p.pub_date for p in queryset]) # Re-use the cache from the evaluation.

#### Quand les objets `QuerySet` ne sont pas mis en cache

Les objets `QuerySet` ne mettent pas toujours leurs résultats en cache. Lorsque seule une partie d’un queryset est évaluée, le cache est consulté mais s’il n’est pas rempli, les éléments renvoyés par la requête suivante ne sont pas mis en cache. Spécifiquement, cela signifie que la restriction d’un jeu de requêtes en employant une segmentation ou un index de liste ne remplira par le cache.

Par exemple, l’interrogation répétée d’un objet `QuerySet` à l’aide d’un index effectue une requête dans la base de données à chaque fois :

    >>> queryset = Entry.objects.all()
    >>> print(queryset[5]) # Queries the database
    >>> print(queryset[5]) # Queries the database again

Cependant, si le jeu de requête complet a déjà été évalué, le cache sera tout de même mis à contribution :

    >>> queryset = Entry.objects.all()
    >>> [entry for entry in queryset] # Queries the database
    >>> print(queryset[5]) # Uses cache
    >>> print(queryset[5]) # Uses cache

Voici quelques exemples d’autres actions qui déclenchent l’évaluation de tout l’objet `QuerySet` et qui par conséquent remplissent le cache :

    >>> [entry for entry in queryset]
    >>> bool(queryset)
    >>> entry in queryset
    >>> list(queryset)

Note

L’affichage simple d’un `QuerySet` ne remplit pas le cache. Ceci parce que l’appel à `__repr__()` ne renvoie qu’un segment du jeu de requête complet.

## Interrogation de `JSONField`

L’implémentation des interrogations est différente pour `JSONField`, principalement en raison de l’existence des transformations de clés. Pour le montrer, nous allons utiliser le modèle d’exemple suivant

    from django.db import models

    class Dog(models.Model):
        name = models.CharField(max_length=200)
        data = models.JSONField(null=True)

        def __str__(self):
            return self.name

### Stockage et requête de `None`

Comme pour les autres champs, le stockage de `None` comme valeur de champ enregistre une valeur SQL `NULL`. Même si ce n’est pas recommandé, il est possible de stocker la valeur scalaire `null` de JSON au lieu du `NULL` SQL en utilisant `Value('null')`.

Quelle que soit la valeur stockée, lorsqu’elle est lue de la base de données, la représentation Python de la valeur scalaire `null` de JSON est la même que pour la valeur SQL `NULL`, c’est-à-dire `None`. Il peut donc être difficile de faire la distinction entre les deux.

Ceci ne s’applique qu’à `None` comme valeur de premier niveau du champ. Si `None` se trouve à l’intérieur d’une structure `list` ou `dict`, elle sera toujours interprétée comme un `null` de JSON.

Lors des requêtes, la valeur `None` sera toujours interprétée comme la valeur `null` de JSON. Pour savoir si un champ possède la valeur SQL `NULL`, utilisez `isnull`:

    >>> Dog.objects.create(name='Max', data=None)  # SQL NULL.
    <Dog: Max>
    >>> Dog.objects.create(name='Archie', data=Value('null'))  # JSON null.
    <Dog: Archie>
    >>> Dog.objects.filter(data=None)
    <QuerySet [<Dog: Archie>]>
    >>> Dog.objects.filter(data=Value('null'))
    <QuerySet [<Dog: Archie>]>
    >>> Dog.objects.filter(data__isnull=True)
    <QuerySet [<Dog: Max>]>
    >>> Dog.objects.filter(data__isnull=False)
    <QuerySet [<Dog: Archie>]>

Sauf dans le cas où vous souhaitez vraiment travailler avec des valeurs SQL `NULL`, préférez le paramètre `null=False` et définissez une valeur par défaut convenable pour les valeurs vides, telle que `default=dict`.

Note

Le stockage de la valeur scalaire JSON `null` ne viole pas `null=False`.

### Transformations de clé, d’indice et de chemin

Pour rechercher en fonction d’une clé de dictionnaire donnée, utilisez cette clé comme nom de requête :

    >>> Dog.objects.create(name='Rufus', data={
    ...     'breed': 'labrador',
    ...     'owner': {
    ...         'name': 'Bob',
    ...         'other_pets': [{
    ...             'name': 'Fishy',
    ...         }],
    ...     },
    ... })
    <Dog: Rufus>
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': None})
    <Dog: Meg>
    >>> Dog.objects.filter(data__breed='collie')
    <QuerySet [<Dog: Meg>]>

Il est possible d’enchaîner plusieurs clés pour former une recherche de chemin :

    >>> Dog.objects.filter(data__owner__name='Bob')
    <QuerySet [<Dog: Rufus>]>

Si la clé est un entier, elle sera interprétée comme une transformation d’indice de tableau :

    >>> Dog.objects.filter(data__owner__other_pets__0__name='Fishy')
    <QuerySet [<Dog: Rufus>]>

Si la clé avec laquelle vous souhaitez rechercher entre en conflit avec le nom d’une recherche existante, utilisez la recherche `contains` à la place.

Pour rechercher des clés manquantes, utilisez l’expression de recherche `isnull`:

    >>> Dog.objects.create(name='Shep', data={'breed': 'collie'})
    <Dog: Shep>
    >>> Dog.objects.filter(data__owner__isnull=True)
    <QuerySet [<Dog: Shep>]>

Note

Les exemples de requêtes ci-dessus utilisent implicitement la recherche `exact`. Les transformations de clé, d’indice et de chemin peuvent aussi être chaînées avec : `icontains`, `endswith`, `iendswith`, `iexact`, `regex`, `iregex`, `startswith`, `istartswith`, `lt`, `lte`, `gt` et `gte`, tout comme avec Requêtes de contenance et de clé.

Note

En raison de la façon dont les requêtes clé-chemin fonctionnent, `exclude()` et `filter()` ne garantissent pas la production d’ensembles exhaustifs. Si vous souhaitez inclure les objets pour lesquels le chemin n’existe pas, ajoutez l’expression `isnull`.

Avertissement

Comme n’importe quelle chaîne peut être une clé d’un objet JSON, toute recherche autre que celles mentionnées ci-dessous sera interprétée comme une recherche par clé. Aucune erreur n’est produite. Faites spécialement attention aux erreurs de frappe et vérifiez systématiquement que vos requêtes fonctionnent correctement.

Utilisateurs MariaDB et Oracle

Quand on utilise `order_by()` sur une transformation de clé, d’indice ou de chemin, le tri des objets se fait sur la représentation textuelle des valeurs. Ceci se produit parce que les bases de données MariaDB et Oracle ne fournissent pas de fonction pour convertir les valeurs JSON en leur valeur SQL équivalente.

Utilisateurs Oracle

Pour les bases de données Oracle, l’utilisation de `None` comme valeur de requête dans une requête `exclude()` renvoie des objets qui n’ont pas `null` comme valeur sur le chemin indiqué, incluant aussi les objets qui n’ont pas le chemin du tout. Avec les autres moteurs de base de données, la requête renvoie les objets où le chemin indiqué existe et la valeur n’est pas `null`.

Utilisateurs de PostgreSQL

Avec PostgreSQL, si une seule clé ou indice est donnée, l’opérateur SQL `->` est utilisé. Si plusieurs opérateurs sont donnés, alors c’est l’opérateur `#>` qui est utilisé.

### Requêtes de contenance et de clé

#### `contains`

La recherche `contains` est surchargée pour les champs `JSONField`. Les objets renvoyés sont ceux pour qui le dictionnaire de paires clé-valeur est totalement contenu au premier niveau du champ. Par exemple :

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
    <Dog: Rufus>
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
    <Dog: Meg>
    >>> Dog.objects.create(name='Fred', data={})
    <Dog: Fred>
    >>> Dog.objects.filter(data__contains={'owner': 'Bob'})
    <QuerySet [<Dog: Rufus>, <Dog: Meg>]>
    >>> Dog.objects.filter(data__contains={'breed': 'collie'})
    <QuerySet [<Dog: Meg>]>

Oracle et SQLite

`contains` n’est pas pris en charge avec Oracle et SQLite.

#### `contained_by`

Il s’agit de l’inverse de la recherche `contains`, les objets renvoyés sont ceux pour qui les paires de clé-valeur forment un sous-ensemble des valeurs transmises. Par exemple :

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador', 'owner': 'Bob'})
    <Dog: Rufus>
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
    <Dog: Meg>
    >>> Dog.objects.create(name='Fred', data={})
    <Dog: Fred>
    >>> Dog.objects.filter(data__contained_by={'breed': 'collie', 'owner': 'Bob'})
    <QuerySet [<Dog: Meg>, <Dog: Fred>]>
    >>> Dog.objects.filter(data__contained_by={'breed': 'collie'})
    <QuerySet [<Dog: Fred>]>

Oracle et SQLite

`contained_by` n’est pas pris en charge avec Oracle et SQLite.

#### `has_key`

Renvoie les objets où la clé donnée se trouve au premier niveau des données. Par exemple :

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
    <Dog: Rufus>
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
    <Dog: Meg>
    >>> Dog.objects.filter(data__has_key='owner')
    <QuerySet [<Dog: Meg>]>

#### `has_keys`

Renvoie les objets où toutes les clés données se trouvent au premier niveau des données. Par exemple :

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
    <Dog: Rufus>
    >>> Dog.objects.create(name='Meg', data={'breed': 'collie', 'owner': 'Bob'})
    <Dog: Meg>
    >>> Dog.objects.filter(data__has_keys=['breed', 'owner'])
    <QuerySet [<Dog: Meg>]>

#### `has_any_keys`

Renvoie les objets où au moins une des clés données se trouve au premier niveau des données. Par exemple :

    >>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
    <Dog: Rufus>
    >>> Dog.objects.create(name='Meg', data={'owner': 'Bob'})
    <Dog: Meg>
    >>> Dog.objects.filter(data__has_any_keys=['owner', 'breed'])
    <QuerySet [<Dog: Rufus>, <Dog: Meg>]>

## Requêtes complexes avec des objets `Q`

Les requêtes à paramètres nommés (dans `filter()`, etc.) sont combinées par `AND` (ET). 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`.

Un `objet Q` (`django.db.models.Q`) est un objet utilisé pour englober plusieurs paramètre nommés. Ces paramètre nommés sont indiqués comme pour les « Recherches dans les champs » ci-dessus.

Par exemple, cet objet `Q` représente une seule requête `LIKE`:

    from django.db.models import Q
    Q(question__startswith='What')

Les objets `Q` peuvent être combinés à l’aide des opérateurs `&` et `|`. Lorsqu’un opérateur est utilisé avec deux objets `Q`, cela produit un nouvel objet `Q`.

Par exemple, cette ligne produit un seul objet `Q` représentant la combinaison par « OR » de deux requêtes `"question__startswith"`:

    Q(question__startswith='Who') | Q(question__startswith='What')

C’est équivalent à la clause SQL `WHERE` ci-dessous :

    WHERE question LIKE 'Who%' OR question LIKE 'What%'

Vous pouvez composer des instructions de complexité arbitraire en combinant des objets `Q` avec les opérateurs `&` et `|` et en les groupant par des parenthèses. De même, les objets `Q` peuvent être inversés par l’opérateur de négation `~`, permettant à des requêtes combinées d’utiliser à la fois des requêtes normales et des requêtes inversées (`NOT`) :

    Q(question__startswith='Who') | ~Q(pub_date__year=2005)

Chaque fonction de recherche acceptant des paramètres nommés (par ex. `filter()`, `exclude()`, `get()`) peut aussi recevoir un ou plusieurs objets `Q` comme paramètre positionnel (non nommé). Si vous indiquez plusieurs objets `Q` comme paramètres d’une fonction de recherche, les paramètres seront combinés avec « AND ». Par exemple :

    Poll.objects.get(
        Q(question__startswith='Who'),
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
    )

… se traduit grossièrement en SQL par :

    SELECT * from polls WHERE question LIKE 'Who%'
        AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

Les fonctions de recherche peuvent mélanger l’utilisation d’objets `Q` et de paramètres nommés. Tous les paramètres fournis à une fonction de recherche (que ce soit des paramètres nommés ou des objets `Q`) sont combinés par l’opérateur « AND ». Cependant, si un objet `Q` est fourni, il doit précéder toute définition de paramètre nommé. Par exemple :

    Poll.objects.get(
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
        question__startswith='Who',
    )

… correspond à une requête valable, équivalente à l’exemple précédent ; mais :

    # INVALID QUERY
    Poll.objects.get(
        question__startswith='Who',
        Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
    )

… n’est pas correct.

Voir aussi

Les exemples de requêtes OR dans les tests unitaires de Django montrent quelques utilisations possibles de `Q`.

## Comparaison d’objets

Pour comparer deux instances de modèle, utilisez l’opérateur de comparaison standard de Python, le double signe égal : `==`. En arrière-plan, ce sont les valeurs clés primaires des deux modèles qui sont comparées.

En utilisant l’exemple `Entry` ci-dessus, les deux instructions suivantes sont équivalentes :

    >>> some_entry == other_entry
    >>> some_entry.id == other_entry.id

Si la clé primaire d’un modèle ne s’appelle pas `id`, aucun problème. Les comparaisons utilisent toujours la clé primaire, quel que soit son nom. Par exemple, si un champ clé primaire d’un modèle s’appelle `name`, ces deux lignes sont équivalentes :

    >>> some_obj == other_obj
    >>> some_obj.name == other_obj.name

## Suppression d’objets

La méthode de suppression se nomme `delete()`. Cette méthode supprime immédiatement l’objet et renvoie le nombre d’objets supprimés ainsi qu’un dictionnaire avec le nombre de suppressions par type d’objet. Exemple :

    >>> e.delete()
    (1, {'weblog.Entry': 1})

Il est aussi possible de supprimer des objets groupés. Chaque `QuerySet` comporte une méthode `delete()` qui supprime tous les objets contenus dans l’objet `QuerySet`.

Par exemple, cette commande supprime tous les objets `Entry` dont l’année de `pub_date` est 2005 :

    >>> Entry.objects.filter(pub_date__year=2005).delete()
    (5, {'webapp.Entry': 5})

Sachez toutefois que cette opération sera autant que possible exécutée purement au niveau SQL, ce qui signifie que les méthodes `delete()` des instances individuelles ne seront pas forcément appelées durant le processus. Si vous avez écrit une méthode `delete()` personnalisée dans une classe de modèle et que vous voulez être certain qu’elle soit appelée, vous devrez supprimer « manuellement » les instances de ce modèle (par ex. en itérant sur un objet `QuerySet` et en appelant explicitement `delete()` sur chaque instance) plutôt que d’employer la méthode de suppression groupée `delete()` de l’objet `QuerySet`.

Lorsque Django supprime un objet, il émule par défaut le comportement de la contrainte SQL `ON DELETE CASCADE`. En d’autres termes, tout objet possédant des clés étrangères vers l’objet en cours de suppression seront également supprimés. Par exemple :

    b = Blog.objects.get(pk=1)
    # This will delete the Blog and all of its Entry objects.
    b.delete()

Ce comportement en cascade peut être personnalisé au moyen du paramètre `on_delete` de la classe `ForeignKey`.

Notez que `delete()` est la seule méthode de `QuerySet` qui n’est pas exposée sur un objet `Manager`. Il s’agit d’un mécanisme de sécurité pour vous empêcher d’exécuter accidentellement `Entry.objects.delete()` ce qui supprimerait toutes les lignes. Si vous souhaitez vraiment supprimer tous les objets, vous devez alors indiquer explicitement une requête contenant tous les objets :

    Entry.objects.all().delete()

## Copie des instances de modèles

Même s’il n’existe pas de méthode intégrée pour la copie d’instances de modèles, il est possible de créer facilement de nouvelles instances en copiant toutes les valeurs des champs d’une autre instance. Dans le cas le plus simple, il suffit de définir `pk` à `None`. En utilisant notre exemple de blogue :

    blog = Blog(name='My blog', tagline='Blogging is easy')
    blog.save() # blog.pk == 1

    blog.pk = None
    blog.save() # blog.pk == 2

Les choses se compliquent lorsqu’il y a de l’héritage. Considérons une sous-classe de `Blog`:

    class ThemeBlog(Blog):
        theme = models.CharField(max_length=200)

    django_blog = ThemeBlog(name='Django', tagline='Django is easy', theme='python')
    django_blog.save() # django_blog.pk == 3

Due to how inheritance works, you have to set both `pk` and `id` to `None`:

    django_blog.pk = None
    django_blog.id = None
    django_blog.save() # django_blog.pk == 4

Ce processus ne copie pas les relations ne faisant pas partie de la table de base de données du modèle. Par exemple, `Entry` possède un champ `ManyToManyField` vers `Author`. Après avoir dupliqué un objet « entry », vous devez définir les relations plusieurs-à-plusieurs vers le nouvel objet :

    entry = Entry.objects.all()[0] # some previous entry
    old_authors = entry.authors.all()
    entry.pk = None
    entry.save()
    entry.authors.set(old_authors)

Pour un champ `OneToOneField`, vous devez dupliquer l’objet lié et l’attribuer au champ correspondant du nouvel objet pour éviter la rupture de la contrainte unique du champ un-à-un. Par exemple, en supposant que `entry` a déjà été dupliqué comme ci-dessus :

    detail = EntryDetail.objects.all()[0]
    detail.pk = None
    detail.entry = entry
    detail.save()

## Mise à jour simultanée de plusieurs objets

Il peut arriver que vous souhaitiez définir la valeur d’un certain champ pour tous les objets d’un `QuerySet`. C’est faisable à l’aide de la méthode `update()`. Par exemple :

    # Update all the headlines with pub_date in 2007.
    Entry.objects.filter(pub_date__year=2007).update(headline='Everything is the same')

Seuls les champs qui ne sont pas des relations et les champs `ForeignKey` peuvent être mis à jour avec cette méthode. Pour mettre à jour un champ qui ne représente pas une relation, indiquez la nouvelle valeur sous forme de constante. Pour mettre à jour un champ `ForeignKey`, indiquez la nouvelle valeur sous forme d’une instance de modèle vers laquelle le champ devra pointer. Par exemple :

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

    # Change every Entry so that it belongs to this Blog.
    >>> Entry.objects.all().update(blog=b)

La méthode `update()` est appliquée immédiatement et renvoie le nombre de lignes correspondant à la requête (ce qui ne correspond pas toujours au nombre de lignes mises à jour si certaines lignes ont déjà la bonne valeur). La seule restriction sur l’objet `QuerySet` mis à jour est qu’il ne peut accéder qu’à une seule table de base de données, la table principale du modèle. Vous pouvez filtrer selon des champs liés, mais vous ne pouvez mettre à jour des colonnes que dans la table principale du modèle. Exemple :

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

    # Update all the headlines belonging to this Blog.
    >>> Entry.objects.filter(blog=b).update(headline='Everything is the same')

Soyez conscient que la méthode `update()` est directement convertie en instruction SQL. Il s’agit d’une opération groupée pour des mises à jour directes. Elle ne fait appel à aucune méthode `save()` des modèles, n’émet aucun signal `pre_save` ou `post_save` (qui sont des conséquences de l’appel à `save()`) et ne respecte pas l’option de champ `auto_now`. Si vous souhaitez enregistrer chaque élément d’un objet `QuerySet` tout en garantissant que la méthode `save()` de chaque instance est appelée, vous n’avez pas besoin d’une fonction particulière pour cela. Effectuez une boucle et appelez `save()` pour chaque objet :

    for item in my_queryset:
        item.save()

Les appels à `update` peuvent aussi utiliser les `expressions F` pour mettre à jour un champ en fonction de la valeur d’un autre champ du modèle. C’est particulièrement utile pour incrémenter des compteurs en fonction de leur valeur actuelle. Par exemple, pour incrémenter le nombre de pings de chaque article d’un blogue :

    >>> Entry.objects.all().update(number_of_pingbacks=F('number_of_pingbacks') + 1)

Cependant, au contraire des objets `F()` dans les clauses `filter()` et `exclude()`, il n’est pas autorisé d’introduire des jointures lors de l’utilisation de `F()` dans des mises à jour ; seuls des champs du modèle en cours de mise à jour peuvent être référencés. Si vous essayez d’introduire une jointure avec un objet `F()`, une erreur `FieldError` sera générée :

    # This will raise a FieldError
    >>> Entry.objects.update(headline=F('blog__name'))

## Objets liés

Lorsque vous définissez une relation dans un modèle (par ex. un champ `ForeignKey`, `OneToOneField` ou `ManyToManyField`), les instances de ce modèle disposeront d’une API agréable pour accéder aux objets liés.

En utilisant les modèles définis au sommet de cette page, par exemple, un objet `Entry` `e` peut atteindre son objet `Blog` lié en accédant à l’attribut `blog`: `e.blog`.

(En arrière-plan, cette fonctionnalité est implémentée par des descripteurs Python. Cela n’a pas de conséquence particulière, mais nous le mentionnons pour les curieux).

Django crée également une API d’accession par l’autre côté de la relation, le lien depuis le modèle lié au modèle qui définit la relation. Par exemple, un objet `Blog` `b` peut accéder à une liste de tous les objets `Entry` liés par l’attribut `entry_set`: `b.entry_set.all()`.

Tous les exemples de cette section utilisent les modèles d’exemple `Blog`, `Author` et `Entry` définis au sommet de cette page.

### Relations un-à-plusieurs

#### Sens « descendant »

Si un modèle possède un champ `ForeignKey`, les instances de ce modèle ont accès à l’objet lié par un attribut du modèle.

Exemple :

    >>> e = Entry.objects.get(id=2)
    >>> e.blog # Returns the related Blog object.

Un attribut d’objet lié (clé étrangère) est accessible en lecture et en écriture. Comme l’on peut s’y attendre, les modifications de la clé étrangère ne sont pas enregistrées en base de données tant que `save()` n’a pas été appelée. Exemple :

    >>> e = Entry.objects.get(id=2)
    >>> e.blog = some_blog
    >>> e.save()

Si un champ `ForeignKey` possède `null=True` (c’est-à-dire qu’il autorise les valeurs `NULL`), vous pouvez lui attribuer `None` pour supprimer la relation. Exemple :

    >>> e = Entry.objects.get(id=2)
    >>> e.blog = None
    >>> e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"

L’accès « descendant » aux relations un-à-plusieurs est mis en cache lors du premier accès à l’objet lié. Les accès suivants à la clé étrangère depuis la même instance d’objet se font à partir du cache. Exemple :

    >>> e = Entry.objects.get(id=2)
    >>> print(e.blog)  # Hits the database to retrieve the associated Blog.
    >>> print(e.blog)  # Doesn't hit the database; uses cached version.

Notez que la méthode `select_related()` de `QuerySet` peuple de manière récursive et anticipée le cache de toutes les relations un-à-plusieurs. Exemple :

    >>> e = Entry.objects.select_related().get(id=2)
    >>> print(e.blog)  # Doesn't hit the database; uses cached version.
    >>> print(e.blog)  # Doesn't hit the database; uses cached version.

#### Accès aux relations inverses

Si un modèle possède un champ `ForeignKey`, les instances du modèle de clé étrangère auront accès à un `Manager` renvoyant toutes les instances du premier modèle. Par défaut, ce `Manager` se nomme `XXX_set`, où `XXX` est le nom du modèle source en minuscules. Ce `Manager` renvoie des objets `QuerySet`, qui peuvent être filtrés et manipulés comme le décrit la section « Sélection d’objets » ci-dessus.

Exemple :

    >>> b = Blog.objects.get(id=1)
    >>> b.entry_set.all() # Returns all Entry objects related to Blog.

    # b.entry_set is a Manager that returns QuerySets.
    >>> b.entry_set.filter(headline__contains='Lennon')
    >>> b.entry_set.count()

Il est possible de surcharger le nom `XXX_set` en définissant le paramètre `related_name` dans la définition du champ `ForeignKey`. Par exemple, si le modèle `Entry` était modifié en définissant `blog = ForeignKey(Blog, on_delete=models.CASCADE, related_name='entries')`, l’exemple ci-dessus aurait été écrit comme ceci :

    >>> b = Blog.objects.get(id=1)
    >>> b.entries.all() # Returns all Entry objects related to Blog.

    # b.entries is a Manager that returns QuerySets.
    >>> b.entries.filter(headline__contains='Lennon')
    >>> b.entries.count()

#### Utilisation d’un gestionnaire inverse personnalisé

Par défaut, le gestionnaire `RelatedManager` utilisé pour les relations inverses est une sous-classe du gestionnaire par défaut du modèle. Si vous aimeriez indiquer un autre gestionnaire pour une requête précise, vous pouvez utiliser la syntaxe suivante :

    from django.db import models

    class Entry(models.Model):
        #...
        objects = models.Manager()  # Default Manager
        entries = EntryManager()    # Custom Manager

    b = Blog.objects.get(id=1)
    b.entry_set(manager='entries').all()

Si `EntryManager` effectuait du filtrage par défaut dans sa méthode `get_queryset()`, ce filtrage s’appliquerait à la méthode `all()`.

En indiquant un gestionnaire inverse personnalisé, cela permet aussi d’appeler ses méthodes personnalisées :

    b.entry_set(manager='entries').is_published()

#### Méthodes supplémentaires pour manipuler des objets liés

En plus des méthodes `QuerySet` présentées ci-dessus dans « Sélection d’objets », l’objet `Manager` d’une `ForeignKey` possède des méthodes supplémentaires pour gérer l’ensemble des objets liés. Vous trouverez ci-dessous un résumé de ces méthodes et des détails plus complets peuvent être lus dans la référence des objets liés.

`add(obj1, obj2, ...)`
  Ajoute les objets modèles indiqués à l’ensemble des objets liés.
`create(**kwargs)`
  Crée un nouvel objet, l’enregistre et le place dans l’ensemble des objets liés. Renvoie l’objet nouvellement créé.
`remove(obj1, obj2, ...)`
  Enlève les objets modèles indiqués de l’ensemble des objets liés.
`clear()`
  Enlève tous les objets de l’ensemble des objets liés.
`set(objs)`
  Remplace l’ensemble des objets liés.

Pour définir les membres d’un ensemble d’objets liés, utilisez la méthode `set()` avec une liste d’instances d’objets. Par exemple, si `e1` et `e2` sont des instances `Entry`:

    b = Blog.objects.get(id=1)
    b.entry_set.set([e1, e2])

Si la méthode `clear()` est disponible, tout objet pré-existant sera enlevé de `entry_set` avant que tous les objets de la séquence itérable (dans ce cas, une liste) soient ajoutés à l’ensemble. Si la méthode `clear()` n’est pas disponible, tous les objets de la séquence itérable sont ajoutés sans que les éléments existants ne soient enlevés.

Toute opération « inverse » décrite dans cette section prend immédiatement effet au niveau de la base de données. Tout ajout, création ou suppression est immédiatement et automatiquement enregistré dans la base de données.

### Relations plusieurs-à-plusieurs

Les deux côtés d’une relation plusieurs-à-plusieurs obtiennent automatiquement l’API d’accès à l’autre côté. L’API fonctionne de manière identique à la relation « inverse » d’une relation un-à-plusieurs décrite ci-dessus.

Une des différences tient dans le nommage de l’attribut : le modèle qui définit le champ `ManyToManyField` utilise le nom d’attribut du champ lui-même, alors que le modèle « inverse » utilise le nom de modèle en minuscules du modèle original en y ajoutant `'_set'` (tout comme pour les relations un-à-plusieurs inverses).

Un exemple va rendre tout ceci plus compréhensible :

    e = Entry.objects.get(id=3)
    e.authors.all() # Returns all Author objects for this Entry.
    e.authors.count()
    e.authors.filter(name__contains='John')

    a = Author.objects.get(id=5)
    a.entry_set.all() # Returns all Entry objects for this Author.

Tout comme pour `ForeignKey`, il est possible d’indiquer une valeur `related_name` dans `ManyToManyField`. Dans l’exemple ci-dessus, si le champ `ManyToManyField` de `Entry` était défini avec `related_name='entries'`, chaque instance de `Author` posséderait un attribut `entries` au lieu de `entry_set`.

Une autre différence par rapport aux relations un-à-plusieurs est qu’en plus des instances de modèles, les méthodes `add()`, `set()` et `remove()` des relations plusieurs-à-plusieurs acceptent des valeurs de clé primaire. Par exemple, si `e1` et `e2` sont des instances `Entry`, alors ces appels à `set()` fonctionnent de manière identique

    a = Author.objects.get(id=5)
    a.entry_set.set([e1, e2])
    a.entry_set.set([e1.pk, e2.pk])

### Relations un-à-un

Les relations un-à-un sont très semblables aux relations plusieurs-à-un. Si vous définissez un champ `OneToOneField` dans votre modèle, les instances de ce modèle auront accès à l’objet lié via un attribut du modèle.

Par exemple :

    class EntryDetail(models.Model):
        entry = models.OneToOneField(Entry, on_delete=models.CASCADE)
        details = models.TextField()

    ed = EntryDetail.objects.get(id=2)
    ed.entry # Returns the related Entry object.

La différence survient dans les requêtes « inverses ». Le modèle lié dans une relation un-à-un a aussi accès à un objet `Manager`, mais celui-ci représente un objet unique et non pas une collection d’objets :

    e = Entry.objects.get(id=2)
    e.entrydetail # returns the related EntryDetail object

Si aucun objet n’a été attribué à cette relation, Django génère une exception `DoesNotExist`.

Il est possible d’attribuer des instances à la relation inverse sur le même principe que pour les relations descendantes :

    e.entrydetail = ed

### Comment la relation inverse est-elle possible ?

D’autres interfaces d’abstraction objet-relationnel exigent de définir les relations des deux côtés. Les développeurs Django pensent qu’il s’agit d’une violation du principe DRY (Don’t Repeat Yourself, ne pas se répéter), c’est pourquoi Django ne demande de définir la relation que d’un seul côté.

Mais comment est-ce possible, dans la mesure où une classe de modèle ne sait pas quelles autres classes de modèles lui sont liées avant que ces autres classes soient elles-mêmes chargées ?

La réponse se trouve dans le `registre des applications`. Lorsque Django démarre, il importe chaque application figurant dans `INSTALLED_APPS`, puis le module `models` dans chaque application. Chaque fois qu’une nouvelle classe est créée, Django ajoute les relations inverses aux modèles liés. Si les modèles liés n’ont pas encore été importés, Django garde la trace de ces relations et les complète au moment où les modèles concernés sont finalement importés.

C’est pour cette raison qu’il est particulièrement important que tous les modèles utilisés soient définis dans des applications qui figurent dans `INSTALLED_APPS`. Sinon, les relations inverses pourraient ne pas fonctionner correctement.

### Les requêtes sur les objets liés

Les requêtes impliquant des objets liés suivent les mêmes règles que les requêtes contenant des valeurs de champs normales. Pour indiquer la valeur à laquelle doit correspondre une requête, vous pouvez utiliser soit une instance de l’objet lui-même, soit la valeur de clé primaire de l’objet.

Par exemple, si vous avez un objet `Blog` `b` avec `id=5`, les trois requêtes suivantes sont identiques :

    Entry.objects.filter(blog=b) # Query using object instance
    Entry.objects.filter(blog=b.id) # Query using id from instance
    Entry.objects.filter(blog=5) # Query using id directly

## Recours au code SQL brut

Si vous rencontrez le besoin de devoir écrire une requête SQL trop complexe pour l’abstraction de base de données de Django, il peut être nécessaire d’écrire le code SQL à la main. Django offre quelques options pour l’écriture de requêtes SQL brutes ; voir Lancement de requêtes SQL brutes.

Finalement, il est important de noter que la couche de base de données de Django n’est qu’une interface vers votre base de données. Vous pouvez accéder à votre base de données par d’autres outils, langages de programmation ou environnements de base de données ; il n’y a rien de spécifique à Django en ce qui concerne la base de données.