web-dev-qa-db-fra.com

Quand dois-je utiliser un gestionnaire personnalisé par rapport à un ensemble de requêtes personnalisé dans Django?

Dans Django, les gestionnaires personnalisés sont un excellent moyen d'organiser une logique de requête réutilisable. La documentation Django sur Gestionnaires personnalisés dit:

Il y a deux raisons pour lesquelles vous voudrez peut-être personnaliser un Manager: pour ajouter des méthodes supplémentaires Manager et/ou pour modifier les valeurs initiales QuerySet et Manager.

Cependant, il décrit ensuite comment les classes QuerySet personnalisées peuvent également être créées, et que celles-ci peuvent être rendues accessibles directement à partir du modèle de données en tant que gestionnaire à l'aide de QuerySet.as_manager():

L'instance Manager créée par QuerySet.as_manager() sera pratiquement identique à la PersonManager de l'exemple précédent.

Il semble qu'il y ait beaucoup de flexibilité dans la façon d'organiser leur logique entre des classes Manager et/ou QuerySet personnalisées. Quels sont les principes par lesquels je dois décider quand utiliser l'un par rapport à l'autre?

53
John Lehmann

Principalement pour permettre une composition facile des requêtes. Généralement, si vous voulez pouvoir effectuer certaines opérations sur un ensemble de requêtes existant dans une chaîne d'appels de requête, vous pouvez utiliser un QuerySet.

Par exemple, supposons que vous ayez un modèle Image qui a un champ width, height:

class Image(models.Model):
    width = ...  # Width in pixels
    height = ... # Height in pixels

vous pouvez écrire des méthodes QuerySet personnalisées:

class ImageQuerySet(models.QuerySet): 
    def landscapes(self):
        return self.filter(width__gte=models.F('height'))

    def portraits(self):
        return self.filter(width__lte=models.F('height'))

    def small(self):
        return self.filter(width__lte=1200)

    def large(self):
        return self.filter(width__gte=1200)

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

maintenant, vous pouvez facilement créer des ensembles de requêtes dynamiques:

Image.objects.all().portraits().small()
Image.objects.all().large().portraits()

Logiquement, ces fonctions devraient concerner principalement le partitionnement ou la redéfinition des ensembles de requêtes existants du modèle de l'ensemble de requêtes. Pour les situations où vous n'opérez pas sur des ensembles de requêtes existants, vous ne voulez pas du tout renvoyer un ensemble de requêtes, ou vous devrez peut-être exécuter une logique associée qui n'implique pas ce modèle particulier, qu'un gestionnaire de modèle qu'il convient mieux.

30
Timmy O'Mahony

Je n'arrêtais pas de me réapprendre ce qu'est un Manager vs un QuerySet donc, j'ai pensé que je ferais mieux d'écrire ici, alors facilite la prochaine fois que je me le demande.

Un Manager est la classe qui est attachée à votre modèle et renvoie une instance QuerySet, objects étant le gestionnaire par défaut. La plupart des méthodes de gestion, ex. all(), filter() retourne les instances de jeu de requêtes.

Plus en détail, lorsque vous effectuez YourModel.objects.filter(..) vous obtenez une instance de jeu de requêtes. Lorsque vous souhaitez le filtrer à nouveau, vous pouvez chaîner une autre méthode .filter(..) uniquement car elle est également disponible dans la classe QuerySet. C'est ce que vous voulez. Ayez vos méthodes sur le gestionnaire et le jeu de requêtes qu'il renvoie.

Si filter n'était pas également une méthode de gestion, vous devriez faire YourModel.objects.all() pour obtenir le jeu de requêtes, et puis ajoutez la ou les méthodes filter à partir de là.

Pour simplifier les choses, Django définit une méthode as_manager() sur la classe QuerySet qui la transforme en, enfin .., un gestionnaire [docs] =. Par conséquent, vous définissez toutes vos méthodes personnalisées sur votre ensemble de requêtes, vous le transformez en gestionnaire et vous attachez à votre modèle, de sorte que vous pouvez l'appeler la première fois (en tant que méthode de gestionnaire) et l'enchaîner autant de fois que vous le souhaitez. (comme méthodes de jeu de requêtes).

En écrivant cette réponse, je me suis demandé s'il y avait des méthodes de gestionnaire livrées avec Django qui ne sont pas des méthodes de jeu de requêtes, et la première qui m'est venue à l'esprit était la méthode get_or_create Car elle ne semble pas avoir besoin d'un ensemble de requêtes. Mais devinez quoi? cela s'est également avéré être défini sur la classe QuerySet.

Pour faire court, vous voulez presque toujours écrire des méthodes QuerySet et les avoir aussi sur le gestionnaire via la as_manager().

8
mehmet