Skip to content

Instantly share code, notes, and snippets.

@zacharyvoase
Created April 21, 2009 11:20
Show Gist options
  • Save zacharyvoase/99083 to your computer and use it in GitHub Desktop.
Save zacharyvoase/99083 to your computer and use it in GitHub Desktop.
Django Managers for pre-defined queries.
# -*- coding: utf-8 -*-
"""
Managers for pre-defined queries.
Example::
from django.db import models
from qmanager import QManager
class MyModel(models.Model):
# Fields
...
is_hidden = models.BooleanField()
...
# Managers
objects = models.Manager()
public = QManager(models.Q(is_hidden=False))
hidden = ~public # NOT public.
QManagers support combination via ``&`` and ``|``, with each other and also with
instances of ``django.db.models.Q`` (i.e. query objects).
"""
from django.db import models
def metaclass(cls):
if not issubclass(cls, object):
raise TypeError('Class %r does not support metaclasses.' % (cls,))
return getattr(cls, '__metaclass__', type)
def get_query(obj):
if (isinstance(obj, QManager) or
(isinstance(obj, type) and issubclass(obj, QManager)) or
hasattr(obj, 'query')):
return obj.query
elif isinstance(obj, models.Q):
return obj
raise TypeError('Object %r is not a QManager or Query object.' % (obj,))
class QManagerMeta(metaclass(models.Manager)):
def __call__(cls, *args):
if args:
return cls.with_query(*args)()
return super(QManagerMeta, cls).__call__()
def with_query(cls, query):
return type(cls.__name__, (cls,),
{'query': query, '__module__': cls.__module__})
class QManager(models.Manager):
__metaclass__ = QManagerMeta
query = models.Q()
def __and__(self, other):
return type(self)(self.query & get_query(other))
def __or__(self, other):
return type(self)(self.query | get_query(other))
def __invert__(self):
return type(self)(~self.query)
def get_query_set(self):
return super(QManager, self).get_query_set().filter(self.query)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment