# Documentation Django 5.2.8

# Gestionnaires

class Manager

Un gestionnaire (objet `Manager`) est l’interface par laquelle les opérations de requêtes de base de données sont mises à disposition des modèles Django. Il existe au moins un `Manager` pour chaque modèle d’une application Django.

Le fonctionnement des classes `Manager` est documenté dans Création de requêtes; ce document aborde spécifiquement les options de modèles qui personnalisent le comportement des gestionnaires.

## Noms des gestionnaires

Par défaut, Django ajoute un gestionnaire nommé `objects` à chaque classe de modèle Django. Cependant, si vous aimeriez utiliser `objects` comme nom de champ ou que vous aimeriez nommer le gestionnaire autrement que `objects`, vous pouvez le renommer au niveau du modèle. Pour renommer le gestionnaire d’une classe donnée, définissez un attribut de classe de type `models.Manager()` dans le modèle. Par exemple :

    from django.db import models

    class Person(models.Model):
        # ...
        people = models.Manager()

En utilisant cet exemple de modèle, `Person.objects` générera une exception `AttributeError`, mais `Person.people.all()` fournira effectivement la liste de tous les objets `Person`.

## Gestionnaires personnalisés

Vous pouvez utiliser un gestionnaire personnalisé dans un modèle particulier en étendant la classe `Manager` de base et en créant votre propre instance de `Manager` dans votre modèle.

Il y a deux raisons de vouloir personnaliser un gestionnaire : pour lui ajouter des méthodes supplémentaires ou pour modifier l’objet `QuerySet` initial que le gestionnaire renvoie.

### Ajout de méthodes de gestionnaire supplémentaires

L’ajout de méthodes de gestionnaire supplémentaires est la façon privilégiée d’ajouter des fonctionnalités au « niveau table » à des modèles (pour les fonctionnalités au « niveau ligne », c’est-à-dire les fonctions qui agissent sur une seule instance d’un objet de modèle, utilisez les méthodes de modèles et non pas des méthodes de gestionnaire personnalisées).

Par exemple, ce `Manager` personnalisé ajoute une méthode `with_counts()`:

    from django.db import models
    from django.db.models.functions import Coalesce

    class PollManager(models.Manager):
        def with_counts(self):
            return self.annotate(num_responses=Coalesce(models.Count("response"), 0))

    class OpinionPoll(models.Model):
        question = models.CharField(max_length=200)
        objects = PollManager()

    class Response(models.Model):
        poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
        # ...

Avec cet exemple, vous écririez `OpinionPoll.objects.with_counts()` pour obtenir un jeu `QuerySet` d’objets `OpinionPoll` comportant l’attribut supplémentaire `num_responses`.

Une méthode de gestionnaire personnalisée peut renvoyer tout ce qu’on veut, elle n’est pas tenue de renvoyer un objet `QuerySet`.

Une autre chose à relever est que les méthodes de gestionnaire ont accès à `self.model` pour obtenir la classe de modèle à laquelle elles sont liées.

### Modification des `QuerySet` initiaux des gestionnaires

Le `QuerySet` de base d’un gestionnaire renvoie tous les objets du système. Par exemple, en utilisant ce modèle :

    from django.db import models

    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)

…l’instruction `Book.objects.all()` renvoie tous les livres de la base de données.

Vous pouvez surcharger le `QuerySet` de base d’un gestionnaire en surchargeant la méthode `Manager.get_queryset()`. `get_queryset()` doit renvoyer un objet `QuerySet` doté des propriétés nécessaires.

Par exemple, le modèle suivant possède deux gestionnaires, un qui renvoie tous les objets et un autre qui ne renvoie que les livres de Roald Dahl :

    # First, define the Manager subclass.
    class DahlBookManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(author="Roald Dahl")

    # Then hook it into the Book model explicitly.
    class Book(models.Model):
        title = models.CharField(max_length=100)
        author = models.CharField(max_length=50)

        objects = models.Manager()  # The default manager.
        dahl_objects = DahlBookManager()  # The Dahl-specific manager.

Avec cet exemple de modèle, `Book.objects.all()` renvoie tous les livres de la base de données, mais `Book.dahl_objects.all()` ne retourne que ceux qui ont été écrits par Roald Dahl.

Comme `get_queryset()` renvoie un objet `QuerySet`, vous pouvez appliquer `filter()`, `exclude()` et toutes les autres méthodes de `QuerySet`. Ainsi, ces instructions sont toutes valables :

    Book.dahl_objects.all()
    Book.dahl_objects.filter(title="Matilda")
    Book.dahl_objects.count()

Cet exemple a aussi mis en évidence une autre technique intéressante : l’emploi de plusieurs gestionnaires dans un même modèle. Vous pouvez lier autant d’instances de gestionnaires que vous voulez à un modèle. C’est une manière non répétitive de définir des « filtres » fréquemment utilisés dans des modèles.

Par exemple :

    class AuthorManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(role="A")

    class EditorManager(models.Manager):
        def get_queryset(self):
            return super().get_queryset().filter(role="E")

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
        people = models.Manager()
        authors = AuthorManager()
        editors = EditorManager()

Cet exemple permet d’effectuer les requêtes `Person.authors.all()`, `Person.editors.all()` et `Person.people.all()` en sachant à quoi vous attendre au niveau des résultats.

### Gestionnaires par défaut

Model._default_manager

Si vous utilisez des objets `Manager` personnalisés, sachez que le premier `Manager` que Django rencontre (dans l’ordre où ils ont été définis dans le modèle) reçoit un statut spécial. Django interprète le premier gestionnaire défini dans une classe comme le gestionnaire par défaut, et plusieurs parties de Django (y compris `dumpdata`) utilisent exclusivement ce gestionnaire pour le modèle en question. En conséquence, il est conseillé de choisir avec prudence le gestionnaire par défaut afin d’éviter une situation où la surcharge de `get_queryset()` aboutit à l’incapacité de récupérer des objets avec lesquels vous avez besoin de travailler.

Vous pouvez définir un gestionnaire par défaut personnalisé en utilisant `Meta.default_manager_name`.

Si par exemple vous écrivez du code qui doit gérer un modèle inconnu dans une application tierce qui implémente une vue générique, utilisez ce gestionnaire (ou `_base_manager`) plutôt que de supposer que le modèle possède un gestionnaire `objects`.

### Gestionnaires de base

Model._base_manager

#### Utilisation de gestionnaires pour accéder aux objets liés

Par défaut, Django utilise une instance de classe de gestionnaire `Model._base_manager` pour accéder aux objets liés (par ex. `choice.question`), et non pas le gestionnaire `_default_manager` de l’objet lié. Ceci parce que Django doit absolument être capable de récupérer l’objet lié, même dans les cas où il serait filtré (et donc inaccessible) par son gestionnaire par défaut.

Si la classe de gestionnaire de base (`django.db.models.Manager`) ne convient pas dans un cas particulier, vous pouvez dire à Django quelle classe utiliser en définissant `Meta.base_manager_name`.

Les gestionnaires de base ne sont pas utilisés lors de requêtes à partir de modèles liés ou lors d’accès aux relations un-à-un ou plusieurs-à-plusieurs. Par exemple, si le modèle `Question` du tutoriel avait un champ `deleted` et un gestionnaire de base qui excluait les instances ayant `deleted=True`, une requête telle que `Choice.objects.filter(question__name__startswith='What')` inclurait aussi les choix liés aux questions supprimées.

#### Ne jamais filtrer les résultats dans ce type de sous-classe de gestionnaire

Ce gestionnaire est utilisé pour accéder aux objets liés à partir d’un autre modèle. Dans ces situations, Django doit être capable de voir tous les objets du modèle qu’il récupère, afin que tout ce qui est référencé puisse être récupéré.

Pour cette raison, vous ne devez pas surcharger `get_queryset()` pour exclure certaines lignes. Si vous le faites, Django renverra des résultats incomplets.

### Appel personnalisé de méthodes `QuerySet` depuis le gestionnaire

Alors que la plupart des méthodes d’un `QuerySet` standard sont directement accessibles à partir d’un `Manager`, ce n’est le cas pour les méthodes supplémentaires définies sur un `QuerySet` personnalisé que si vous les implémentez également sur le `Manager`:

    class PersonQuerySet(models.QuerySet):
        def authors(self):
            return self.filter(role="A")

        def editors(self):
            return self.filter(role="E")

    class PersonManager(models.Manager):
        def get_queryset(self):
            return PersonQuerySet(self.model, using=self._db)

        def authors(self):
            return self.get_queryset().authors()

        def editors(self):
            return self.get_queryset().editors()

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
        role = models.CharField(max_length=1, choices={"A": _("Author"), "E": _("Editor")})
        people = PersonManager()

Cet exemple permet d’appeler `authors()` et `editors()` directement depuis le gestionnaire `Person.people`.

### Création d’objet `Manager` avec des méthodes de `QuerySet`

En lieu et place de l’approche ci-dessus qui nécessite de dupliquer les méthodes à la fois sur les objets `QuerySet` et `Manager`, `QuerySet.as_manager()` peut être utilisé pour créer une instance de `Manager` avec une copie des méthodes d’un objet `QuerySet` personnalisé :

    class Person(models.Model):
        ...
        people = PersonQuerySet.as_manager()

L’instance de `Manager` créée par `QuerySet.as_manager()` sera pratiquement identique au `PersonManager` de l’exemple précédent.

Toutes les méthodes `QuerySet` n’ont pas forcément de sens au niveau `Manager`; par exemple, nous empêchons volontairement la méthode `QuerySet.delete()` d’être copiée vers la classe `Manager`.

Les méthodes sont copiées selon les règles suivantes :

- Les méthodes publiques sont copiées par défaut.

- Les méthodes privées (commençant par un soulignement) ne sont pas copiées par défaut.

- Les méthodes avec un attribut `queryset_only` à `False` sont toujours copiées.

- Les méthodes avec un attribut `queryset_only` à `True` ne sont jamais copiées.

Par exemple :

    class CustomQuerySet(models.QuerySet):
        # Available on both Manager and QuerySet.
        def public_method(self):
            return

        # Available only on QuerySet.
        def _private_method(self):
            return

        # Available only on QuerySet.
        def opted_out_public_method(self):
            return

        opted_out_public_method.queryset_only = True

        # Available on both Manager and QuerySet.
        def _opted_in_private_method(self):
            return

        _opted_in_private_method.queryset_only = False

#### `from_queryset()`

classmethod from_queryset(queryset_class)

Pour une utilisation plus avancée, il peut être souhaitable d’avoir à la fois un `Manager` personnalisé et un `QuerySet` personnalisé. Vous pouvez le faire en appelant `Manager.from_queryset()` qui renvoie une sous-classe du `Manager` de base avec une copie des méthodes `QuerySet` personnalisées :

    class CustomManager(models.Manager):
        def manager_only_method(self):
            return

    class CustomQuerySet(models.QuerySet):
        def manager_and_queryset_method(self):
            return

    class MyModel(models.Model):
        objects = CustomManager.from_queryset(CustomQuerySet)()

Vous pouvez également stocker la classe générée dans une variable :

    MyManager = CustomManager.from_queryset(CustomQuerySet)

    class MyModel(models.Model):
        objects = MyManager()

### Gestionnaires personnalisés et héritage de modèle

Voici comment Django gère les gestionnaires personnalisés dans le contexte d’héritage des modèles:

1. Les gestionnaires des classes de base sont toujours hérités par les classes enfants, par le moyen Python habituel de l’ordre de résolution de nom (les noms des classes enfants surchargent ceux de leurs parents).

2. Si aucun gestionnaire n’est déclaré dans un modèle ou dans ses parents, Django crée automatiquement le gestionnaire `objects`.

3. Le gestionnaire par défaut d’une classe est soit celui qui est choisi par `Meta.default_manager_name`, soit le premier gestionnaire déclaré dans le modèle, soit le gestionnaire par défaut du premier modèle parent.

Ces règles assurent la souplesse nécessaire permettant d’installer un ensemble de gestionnaires personnalisés sur un groupe de modèles via une classe de base abstraite, tout en personnalisant aussi le gestionnaire par défaut. Prenons l’exemple de cette classe de base :

    class AbstractBase(models.Model):
        # ...
        objects = CustomManager()

        class Meta:
            abstract = True

Si vous l’utilisez directement dans une classe enfant, `objects` sera le gestionnaire par défaut si aucun gestionnaire n’est déclaré dans la classe enfant :

    class ChildA(AbstractBase):
        # ...
        # This class has CustomManager as the default manager.
        pass

Si vous voulez hériter de `AbstractBase`, mais avec un autre gestionnaire par défaut, vous pouvez définir le gestionnaire par défaut dans la classe enfant :

    class ChildB(AbstractBase):
        # ...
        # An explicit default manager.
        default_manager = OtherManager()

Ici, `default_manager` est le gestionnaire par défaut. Le gestionnaire `objects` est toujours disponible, puisqu’il est hérité, mais il n’est plus le gestionnaire par défaut.

Pour terminer avec cet exemple, supposons que vous vouliez ajouter des gestionnaires supplémentaires dans la classe enfant tout en conservant le gestionnaire par défaut de `AbstractBase`. Vous ne pouvez pas ajouter directement le nouveau gestionnaire dans la classe enfant, car cela surchargerait le gestionnaire par défaut et vous devriez aussi inclure explicitement tous les gestionnaires de la classe de base abstraite. La solution est de placer les gestionnaires supplémentaires dans une autre classe de base et introduire celle-ci dans la hiérarchie d’héritage après ceux par défaut :

    class ExtraManager(models.Model):
        extra_manager = OtherManager()

        class Meta:
            abstract = True

    class ChildC(AbstractBase, ExtraManager):
        # ...
        # Default manager is CustomManager, but OtherManager is
        # also available via the "extra_manager" attribute.
        pass

Notez que même si vous pouvez définir un gestionnaire personnalisé dans le modèle abstrait, vous ne pouvez appeler aucune de ses méthodes au travers du modèle abstrait. C’est-à-dire :

    ClassA.objects.do_something()

est légal, mais :

    AbstractBase.objects.do_something()

générera une exception. C’est parce que les gestionnaires sont censés intégrer la logique de gestion d’ensembles d’objets. Comme il n’est pas possible d’avoir un ensemble d’objets abstraits, leur gestion n’a pas de sens. Si vous gérez des fonctionnalités s’appliquant au modèle abstrait, vous devriez les placer dans une méthode `staticmethod` ou `classmethod` du modèle abstrait.

### Détails d’implémentation

Quelles que soient les fonctionnalités ajoutées à un gestionnaire personnalisé, il doit toujours être possible de faire une copie légère (« shallow ») d’une de ses instances ; c’est-à-dire que le code suivant doit fonctionner :

    >>> import copy
    >>> manager = MyManager()
    >>> my_copy = copy.copy(manager)

Django effectue des copies légères des objets de gestionnaire durant certaines requêtes ; si votre gestionnaire ne peut pas être copié, ces requêtes échoueront.

Ce ne sera pas un problème pour la plupart des gestionnaires personnalisés. Si vous ne faites qu’ajouter des méthodes simples à votre classe `Manager`, il est improbable que vous empêchiez la copie de votre gestionnaire sans le vouloir. Cependant, si vous surchargez `__getattr__` ou d’autres méthodes privées de l’objet `Manager` qui contrôlent l’état de l’objet, il faut vous assurer que vous n’altériez pas la capacité de votre gestionnaire d’être copié.