Login

Easier chainability with custom QuerySets

Author:
bendavis78
Posted:
March 11, 2012
Language:
Python
Version:
1.3
Tags:
model manager queryset
Score:
2 (after 2 ratings)

Django allows you to specify your own ModelManager with custom methods. However, these methods are chainable. That is, if you have a method on your PersonManager caled men(), you can't do this:

Person.objects.filter(birth_date__year=1978).men()

Normally, this isn't a problem, however your app may be written to take advantage of the chainability of querysets. For example, you may have an API method which may return a filtered queryset. You would want to call with_counts() on an already filtered queryset.

In order to overcome this, we want to override django's QuerySet class, and then make the Manager use this custom class.

The only downside is that your functions will not be implemented on the manager itself, so you'd have to call Person.objects.all().men() instead of Person.objects.men(). To get around this you must also implement the methods on the Manager, which in turn call the custom QuerySet method.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from django.db import models
from django.db.models.query import QuerySet

class PersonQuerySet(QuerySet):
    def men(self):
        return self.filter(sex='m')
    def women(self):
        return self.filter(sex='f')

class PersonManager(models.Manager):
    def get_query_set(self):
        PersonQuerySet(self.model, using=self._db)
    def men(self):
        return self.get_query_set().men()
    def women(self):
        return self.get_query_set().women()
    
class Person(models.Model)
    name = models.CharField()
    birth_date = models.DateField()
    sex = models.CharField(max_length=1)

    objects = PersonManager()

qs = Person.objects.filter(birth_date__year=1978)
qs.men().filter(name__icontains='Bob')

More like this

  1. TaggedManager and TaggedQuerySet with chainable tagged() methods implemented with django-tagging by fish2000 5 years, 1 month ago
  2. Custom managers with chainable filters by itavor 7 years, 2 months ago
  3. Tatsypie: additional list endpoints for custom Model's manager methods by migajek 2 years, 4 months ago
  4. Lightweight querysets by sardarnl 1 year, 9 months ago
  5. Function/Stored Procedure Manager by axiak 7 years, 9 months ago

Comments

martync (on November 6, 2013):

Line 12 : missing "return".

#

raigu (on July 18, 2014):

If you are using Django 1.6+ you should rename get_query_set to get_queryset.

According to Django 1.6 release notes the method is renamed although it is still backward compatible.

#

Please login first before commenting.