How To Add A Custom Managers In Django

Reading Time : ~ .

Django Custom Managers

A Manager is the interface through which database query operations are provided to Django models. At least one Manager exists for every model in a Django application.

Regarding the Manager names:
By default, Django adds a Manager with the name "objects" to every Django model class. However, if you want to use "objects" as a field name (or) if you want to use a name instead of "objects" for the Manager, you can rename it on a per-model basis. To rename the Manager for a given class, define a class attribute of type models.Manager() on that model.
For example:

from django.db import models

class Employee(models.Model):
      gender_choices = (
           ("M", "Male"),
           ("F", "Female")
      )
      roles_choices = (
           ("J", "Junior"),
           ("S", "Senior"),
      )
      first_name = models.CharField(max_length=200)
      last_name = models.CharField(max_length=200)
      email = models.CharField(max_length=250)
      gender = models.CharField(max_length=1, choices=gender_choices)
      role = models.CharField(max_length=120, choices=roles_choices, default="J")
      active = models.BooleanField(default=True)

      # custom manager replaces objects manger
      all_employees = models.Manager()

      def __str__(self):
            return str(self.first_name) + str(self.last_name)

Using the above example model, Employee.objects will throw you an AttributeError exception, but Employee.all_employees.all() will provide a list of all Employee objects.

Now, here we go for the 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.

Note: Manager methods can access self.model to get the model class to which they’re attached.

Here I'm gonna explain Modifying a manager’s initial QuerySet for now:

A Manager’s base QuerySet returns all objects in the system. For example, from the above example using Employee model (except the Custom Manager name):

the statement Employee.objects.all() will return all employees in the database.
You can override a Manager’s base QuerySet by overriding the Manager.get_queryset() method. get_queryset() should return a QuerySet with the properties you require.

For example, the following model has two Managers – one that returns all objects, and one that returns only the active employees:

    # First, define the Manager subclass.
    class EmployeeManager(models.Manager):
        def get_queryset(self):
            return super(EmployeeManager, self).get_queryset().filter(active=True)

    # Then hook it into the Employee model explicitly.
    class Employee(models.Model):
        .....
        active = models.BooleanField(default=True)

        objects = models.Manager() # The default manager.
        active_objects = EmployeeManager() # The EmployeeManager manager.

With this sample model, Employee.objects.all() will return all employees in the database, but Employee.active_objects.all() will only return the ones who are in active state.

Of course, because get_queryset() returns a QuerySet object, you can use filter(), exclude() and all the other QuerySet methods on it. So these statements are all legal:

    Employee.active_objects.all()
    Employee.active_objects.filter(email='employee@gmail.com')
    Employee.active_objects.count()

This example also pointed out another interesting technique: using multiple managers on the same model. You can attach as many Manager() instances to a model as you’d like. This is an easy way to define common “filters” for your models.

For example:

class SeniorManager(models.Manager):
    def get_queryset(self):
        return super(SeniorManager, self).get_queryset().filter(role='S')

class JuniorManager(models.Manager):
    def get_queryset(self):
        return super(JuniorManager, self).get_queryset().filter(role='J')

class Employee(models.Model):
    ...
    roles_choices = (
        ("J", "Junior"),
        ("S", "Senior"),
    )
    ....
    role = models.CharField(max_length=1, choices=role_choices)

    all_employees = models.Manager()
    seniors = SeniorManager()
    juniors = JuniorManager()

This example allows you to request Employee.all_employees.all(), Employee.seniors.all() and Employee.juniors.all() yielding predictable results.

 

Calling custom QuerySet methods from the manager:

While most methods from the standard QuerySet are accessible directly from the Manager, this is only the case for the extra methods defined on a custom QuerySet if you also implement them on the Manager:

class EmployeeQuerySet(models.QuerySet):
    def juniors(self):
        return self.filter(role='J')

    def seniors(self):
        return self.filter(role='S')

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

    def juniors(self):
        return self.get_queryset().juniors()

    def seniors(self):
        return self.get_queryset().seniors()

class Employee(models.Model):
    ...
    roles_choices = (
        ("J", "Junior"),
        ("S", "Senior"),
    )
    ....
    role = models.CharField(max_length=1, choices=role_choices)

    all_employees = EmployeeManager()

This example allows you to call both juniors() and seniors() directly from the manager Employee.all_employees.

 

    By Posted On
SENIOR DEVELOPER at MICROPYRAMID

Need any Help in your Project?Let's Talk

Latest Comments
Related Articles
Sending emails using sendgrid on heroku for a Django App Vinisha Naladala

Integrate Sendgrid API to your Heroku app to deliver simplified emails like any notification emails, user signups etc.

Continue Reading...
Django Custom Template Tags And Filters Nikhila Mergu

Django Template Tags are simple Python functions that accept a value, an optional argument, and return a value to be displayed on the page.
First, ...

Continue Reading...
Add captcha to django web page using Python-reCaptcha Divya Sri

Python-reCaptcha is a pythonic and well-documented reCAPTCHA client that supports all the features of the remote API to generate and verify CAPTCHA challenges. To add ...

Continue Reading...

Subscribe To our news letter

Subscribe to our news letter to receive latest blog posts into your inbox. Please fill your email address in the below form.
*We don't provide your email contact details to any third parties