or

Creating Custom Managers For Repetitive Filters

Today I was trying to do something in Django and I’ve noticed that I’m using lots of filter in my views. And most of the filters were same, but for different purposes. Then I felt like DRY principle is screaming at me. So I started to think that maybe there is a way to prevent these repetitions. And like all other problems in the world, the solution was just in front of my eyes :)

So let’s say that we’ve a model class that represents Employees in the company which includes even retired ones. To reach the all employees, you would use:


Employee.objects.all()

And if you want to work with retired employees:

Employee.objects.filter(status=Employee.RETIRED)

This would give you the all retired employees. If you’re working with this object list frequently, you might want to introduce a custom manager.

Custom Managers

Before going into the custom managers, I’d like to first explain where this Employee.objects comes from. objects attribute is an instance of a special class called Manager (django.db.models.Manager). The basic idea is to provide common db operations via this attribute, e.g all(), filter(), etc.. You can find the full documentation from here. If you don’t specify any custom managers, Django automatically adds this default manager to your model class.

Custom managers on the other hand is the extended version of this manager class. And creating a custom manager is fairly easy:

class MyModel(models.Model):
    myfield = models.CharField(max_length=50)

object_provider = models.Manager()

So above model’s object_provider attribute would act exactly same as the default manager since they’re same. Please check below usages:

'''
  Below usages would provide same results.
'''
MyModel.objects.all()
MyModel.object_provider.all()

So how to customize this manager then? Again, very easy. Just extend the django.db.models.Manager class. So let’s look at the following code:

class RetiredEmployeeManager(models.Manager):
   def get_query_set(self):
      return super(RetiredEmployeeManager, self).get_query_set().filter(status=Employee.RETIRED)

From this point, the only thing you need to do is defining this manager as your manager.

class Employee(models.Model):
    name = models.CharField(max_length=50)

objects = models.Manager()
retired_ones = RetiredEmployeeManager()

And finally, you can use your new manager in your views:

Employee.retired_ones.all();

Hope it helps you to clean up some duplicated code!



Leave a Reply

Name (required)
Mail (required)
Website