Table of Content
- Sample model and model manager
- How to Create a Custom Manager With Chainable QuerySets
- Organizing the Model and Model Manager Codes
- Wrap Off
Most developers who work with Django tend to ignore the capability of the model manager in developing powerful custom querysets for a model. It might also surprise you that some do not know about the Django manager and how it works within a model.
The Django model manager is the interface that Django uses to interact with the database.
The default manager every Django model gets out of the box is the django.db.models.Manager
and it is made available through the Model.objects
property. It is very straightforward to extend it and change the default manager.
The ability to extend and change the default manager makes it possible to create very powerful custom querysets for a django model. It also allows for the possibility of creating a generic behavior for objects throughout the entire application.
In this post, you will learn how to create a custom model manager with a chainable queryset in Django.
Sample model and model manager
Let's work with a model that holds some information about students for our code demo:
Model for Student
from django.db import models
class Student(models.Model):
name = models.CharField(max_length=30)
score = models.PositiveIntegerField(default=0)
hobby = models.CharField(max_length=10, blank=True)
objects = StudentManager()
Model Manager for Student Model
Here's what a typical model manager will look like:
from django.db import models
class StudentManager(models.Manager):
def dance(self):
return self.filter(hobby='dance')
def grade(self, score=95):
return self.filter(score__gt=score)
With the model manager defined above, you will be able to retrieve all students whose hobbies are dance using the line below:
Student.objects.dance()
But, here's something else you should know. The methods we defined above are not chainable. This means that despite being able to still use order_by
or filter
in the result, like below
Student.objects.pdfs().order_by('name')
If you try to chain the methods on themselves, it will break and cause an Attribute error.
Student.objects.pdfs().smaller_than(1000)
AttributeError: 'QuerySet' object has no attribute 'smaller_than'
To make the methods chainable, you must create a custom QuerySet method:
class StudentQuerySet(models.QuerySet):
def dance(self):
return self.filter(hobby='dance')
def grade(self, score=95):
return self.filter(score__gt=score)
Here's what the model manager will now look like:
from django.db import models
class StudentManager(models.Manager):
def get_queryset(self):
return StudentQuerySet(self.model, using=self._db) # Take note of this new method
def dance(self):
return self.self.get_queryset().dance()
def grade(self, score=95):
return self.get_queryset().grade(score)
Now you can use it just like any other QuerySet method:
Student.objects.dance().grade(98).exclude(name='Adam').order_by('name')
If you are only defining custom QuerySets in the Manager, you can simply extend the models.QuerySet
and in the model set the manager as objects = StudentQuerySet.as_manager()
:
class Student(models.Model):
...
objects = StudentQuerySet.as_manager()
Organizing the Model and Model Manager Codes
When you're simply testing something or working on a small project, you can keep the code inside the models.py. But, when working on a project with a propensity for the code base to grow, I recommend you keep the Managers and QuerySets in a different module, named managers.py.
Wrap Off
The Django model manager acts as the interface that Django uses to interact with the database.
The ability to extend and change the default manager makes it possible to create very powerful custom querysets for a django model. It also allows for the possibility of creating a generic behavior for objects throughout the entire application.
If you learned from this tutorial, or it helped you in any way, please consider sharing and subscribing to our newsletter.
Please share this post and for more insightful posts on business, technology, engineering, history, and marketing, subscribe to our newsletter.