Django Create a Custom Manager with Chainable Queries
Django Managers makes handle the database access layer and they are responsible for fetching the rows from a database. In this post, you’ll learn to create a custom manager class and also chain multiple manager methods with chainable querysets.
Creating a Model
First, start by creating a model for our posts app.
In posts\models.py
from django.db import models class PostModel(models.Model): post_id = models.AutoField(primary_key=True) name = models.CharField(max_length=255) content = models.TextField(null=True) is_active = models.IntegerField(default=1) class Meta(): db_table = "posts"
Running Migrations
Next, do the migration for that model by running below two commands.
This command will create a migrations class for PostModel.
python manage.py makemigrations posts
This command will create a PostModel table in a database.
python manage.py migrate
Creating a Custom Manager
Inherit models.Manager
class to create a custom manager.
In posts\models.py
class PostManager(models.Manager): def search_name( self, value ): return self.get_queryset().filter(name__icontains=value) def is_active( self, value=1 ): return self.get_queryset().filter(is_active=value)
We have declared a PostManager class which has two methods. search_name ( which searches the post name ) and is_active ( which set is_active condition ).
Applying Manager class to Model class
class PostModel(models.Model): ... ... objects = PostManager()
post_objects = PostManager()
etc.Calling the Method of Custom Manager
Open shell using command python manage.py shell
from posts.models import PostModel records2 = PostModel.objects.is_active().search_name("my post").all() Traceback (most recent call last): File "", line 1, in AttributeError: 'QuerySet' object has no attribute 'search_name'
The disadvantage to custom managers is that you cannot chain or call methods of managers one after the other. And if you do you’ll see the below error:
AttributeError: 'QuerySet' object has no attribute 'search_name'
Learn more about Django Model Managers in Django Documentation
Creating a Custom Manager with Chainable Queries
We can eliminate the issue of not being able to call multiple methods in Manager by declaring models.QuerySet class.
This is how our manager will look after applying the custom class PostQuerySet.
class PostQuerySet(models.QuerySet): def search_name( self, value ): return self.filter(name__icontains=value) def is_active( self, value=1 ): return self.filter(is_active=value) class PostManager(models.Manager): def get_queryset(self): return PostQuerySet(self.model, using=self._db) def search_name( self, value ): return self.get_queryset().search_name(value) def is_active( self, value=1 ): return self.get_queryset().is_active(value)
Now try to chain manager methods
Open shell again using command python manage.py shell
from posts.models import PostModel records2 = PostModel.objects.is_active().search_name("my post").all()
Chainable Queries without Manager
If you think, using both PostQuerySet and PostManager class is overwhelming then there is a much easier way just by calling PostQuerySet.as_manager().
class PostQuerySet(models.QuerySet): def search_name( self, value ): return self.filter(name__icontains=value) def pk( self, value ): return self.filter(pk=value)
In posts\models.py
class PostModel(models.Model): ... ... objects = PostQuerySet.as_manager()
Using .as_manager() will make class PostQuerySet act as manager for PostModel class.
Now call the query methods
records2 = PostModel.objects.is_active().search_name("my post").all()
This will return all the posts which are active and has `my post` as a name.