- January 23, 2008
- manager queryset
- 10 (after 10 ratings)
The Django docs show us how to give models a custom manager. Unfortunately, filter methods defined this way cannot be chained to each other or to standard queryset filters. Try it:
class NewsManager(models.Manager): def live(self): return self.filter(state='published') def interesting(self): return self.filter(interesting=True) >>> NewsManager().live().interesting() AttributeError: '_QuerySet' object has no attribute 'interesting'
So, instead of adding our new filters to the custom manager, we add them to a custom queryset. But we still want to be able to access them as methods of the manager. We could add stub methods on the manager for each new filter, calling the corresponding method on the queryset - but that would be a blatant DRY violation. A custom
__getattr__ method on the manager takes care of that problem.
And now we can do:
>>> NewsManager().live().interesting() [<NewsItem: ...>]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
from django.db import models class NewsQuerySet(models.query.QuerySet): def live(self): return self.filter(state='published') def interesting(self): return self.filter(interesting=True) class NewsManager(models.Manager): def get_query_set(self): model = models.get_model('news', 'NewsItem') return NewsQuerySet(model) def __getattr__(self, attr, *args): try: return getattr(self.__class__, attr, *args) except AttributeError: return getattr(self.get_query_set(), attr, *args)