QuerySetManager - easily add new QuerySet methods using a Model inner class

 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
from django.db import models

class QuerySetManager(models.Manager):
    def get_query_set(self):
        return self.model.QuerySet(self.model)

# Using it in a model:

from django.db.models.query import QuerySet
import datetime

class Entry(models.Model):
   ...
   objects = QuerySetManager()
   ...
   class QuerySet(QuerySet):
        def on_date(self, date):
            next = date + datetime.timedelta(days = 1)
            return self.filter(
                posted__gt = date,
                posted__lt = next
            )

# Now you can get entries on a specific day like so:
#   Entry.objects.all().on_date(datetime.date.today())

More like this

  1. Pretty print SQL of query sets by peterbe 4 years ago
  2. Add Extra Headers to Test Client Requests by luftyluft 4 years, 10 months ago
  3. Fire Eagle example: views.py from wikinear.com by simon 5 years, 1 month ago
  4. Orderable inlines using drag and drop with jQuery UI by simon 4 years, 8 months ago
  5. Easier chainability with custom QuerySets by bendavis78 1 year, 2 months ago

Comments

dnordberg (on May 6, 2008):

This works for Entry.objects.filter().on_date(date) but not Entry.objects.on_date(date) as some may wish, for this add the following snippet to QuerySetManager.

`

def __getattr__(self, attr, *args):
    try:
        return getattr(self.__class__, attr, *args)
    except AttributeError:
        return getattr(self.get_query_set(), attr, *args)

`

#

exogen (on May 8, 2008):

In response to the above comment, I believe it can simple be written as:

def __getattr__(self, name):
    return getattr(self.get_query_set(), name)

...since the default attribute lookup will check self.class and superclasses.

#

marcoslhc (on February 3, 2010):

There are some articles that deepens the concepts exposed in this snnipet:

-http://simonwillison.net/2008/May/1/orm/

-http://mcarthurgfx.com/blog/article/extending-django-models-managers-and-querysets

#

aehlke (on November 16, 2010):

Also see: http://djangosnippets.org/snippets/2117/

#

clelland (on January 15, 2011):

The simple __getattr__ implementation above no longer works in some cases (as of Django 1.2.4). This replacement does, however:

def __getattr__(self, name, *args):
    if name.startswith('_'):
        raise AttributeError
    return getattr(self.get_query_set(), name, *args)

See ticket 15062 for the whole discussion.

#

zodiac2832 (on July 28, 2011):

I had to modify my manager to the following so I would not receive Pickle Errors.

# pickling causes recursion errors
_deny_methods = ['__getstate__', '__setstate__', '_db']

def __init__(self, queryset_cls=None):
    self._queryset_cls = queryset_cls
    super(PadManager, self).__init__()

def __getattr__(self, name):
    if name in self._deny_methods:
        raise AttributeError(name)
    return getattr(self.get_query_set(), name)

def get_query_set(self):
    return PadQuerySet(self.model)

#

(Forgotten your password?)