Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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 Django documentation on Custom managers says:

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 QuerySet classes can also be created, and that these can be made accessible directly from the data model as a manager using 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 QuerySet classes. What are the principles by which I should decide when to use one versus the other?

like image 846
John Lehmann Avatar asked Apr 22 '15 12:04

John Lehmann


People also ask

Why might you want to write a custom model Manager in Django?

Custom managers. You can use a custom Manager in a particular model by extending the base Manager class and instantiating your custom Manager in your model. 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.

What is the use of QuerySet in Django?

A QuerySet is a collection of data from a database. A QuerySet is built up as a list of objects. QuerySets makes it easier to get the data you actually need, by allowing you to filter and order the data.

What is custom Manager in Django?

It is used to get queryset of objects based on the properties it takes as arguments. If no argument is provided then it will return all the objects. In this example, we create a custom django manager by inheriting Manager class and overriding only the get_queryset method . So we have defined a custom manager .

Is Django QuerySet lazy?

This is because a Django QuerySet is a lazy object. It contains all of the information it needs to populate itself from the database, but will not actually do so until the information is needed.


2 Answers

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.

like image 123
Timmy O'Mahony Avatar answered Sep 21 '22 03:09

Timmy O'Mahony


I kept reteaching myself what is a Manager vs a QuerySet so, I thought I better write here, so make it easier next time I wonder.

A Manager is the class that is attached to your model and returns a QuerySet instance, objects being the default manager. Most manager methods, ex. all(), filter() return queryset instances.

In more detail, when you do YourModel.objects.filter(..) you get a queryset instance. When you want to filter it again, you can chain another .filter(..) method only because it is also available on the QuerySet class too. That is what you want.. have your methods on both the manager and the queryset it returns.

If filter was not also a manager method, you would have to do YourModel.objects.all() to get the queryset, and then add the filter method(s) from there.

To make things easy, Django defines a as_manager() method on the QuerySet class which turns it into a, well.., a manager [docs]. Therefore, you define all your custom methods on your queryset, and turn it into a manager, and attach to your model, so you can call it the first time (as a manager method) and chain it as many times as you want (as queryset methods).

Writing this answer, I wondered if there are any manager methods shipped with Django that aren't queryset methods, and the first that came to my mind was the get_or_create method since it does not seem to need a queryset. But guess what? that also turned out to be defined on the QuerySet class.

Long story short, you almost always want to write QuerySet methods and have them on the manager too via the as_manager().

like image 33
mehmet Avatar answered Sep 21 '22 03:09

mehmet