John Lehmann John Lehmann - 7 months ago 65
Python Question

When should I use a custom Manager versus a custom QuerySet in Django?

In Django, custom Managers are a great way to organize reusable query logic. The docs state that there are two reasons you might want to customize a Manager: to add extra Manager methods, and/or to modify the initial QuerySet the Manager returns.

However, it goes on to describe how custom QuerySets can also be created, and that these can be made accessible directly from the data model as manager via the

QuerySet.as_manager()
. The Manager instance created by QuerySet.as_manager() will be virtually identical to the PersonManager from the previous example.

It seems like there is a lot of flexibility in how one could organize their logic between custom Manager and/or custom QuerySets. Can someone explain the principles by which I should decide when to use one versus the other?

Answer

Mainly to allow for easy composition of queries. Generally if you want to be able perform some operation on an existing queryset in a chain of queryset calls you can use a QuerySet.

For example, say you have an Image model that has a width, height fields:

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

you could write some custom QuerySet methods:

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)

now you can easily create dynamic querysets:

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

Logically, these functions should be concerned primarily with partitioning or redefining of existing querysets of the queryset's model. For situations where you aren't operating on existing querysets, you don't want to return a queryset at all, or you might have to perform some related logic that doesn't involve this particular model, than a model manager it better suited.