How To Add A Custom Managers In Django

Django Custom Managers

A Manager is used to query database operations which will be provided to Django models. Every model in Django application consists at least one Manager by default.

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.

Posted On 05 May 2017 By MicroPyramid


Need any Help in your Project?Let's Talk

Latest Comments
How to maintain user session across sub domains in Django

Nowadays, people are using wildcard domains to provide same user experience across different domains. Using subdomains, we can be able to host multiple sites with …

Continue Reading...
Setting Up Coveralls for Django Project

Coveraslls will check the code coverage for your test cases. To use coveralls.io your code must be hosted on GitHub or BitBucket.

install coveralls
pip …

Continue Reading...
Understanding Checkout flow in Django Oscar.

Explaining Django Oscar checkout flow.

Continue Reading...

Subscribe To our news letter

Subscribe and Stay Updated about our Webinars, news and articles on Django, Python, Machine Learning, Amazon Web Services, DevOps, Salesforce, ReactJS, AngularJS, React Native.
* We don't provide your email contact details to any third parties