from types import ClassType
from django.db.models.manager import Manager
from django.db.models.query import QuerySet
def manager_from(*mixins, **kwds):
'''
Returns a Manager instance with extra methods, also available and
chainable on generated querysets.
:param mixins: Each ``mixin`` can be either a class or a function. The
generated manager and associated queryset subclasses extend the mixin
classes and include the mixin functions (as methods).
:keyword queryset_cls: The base queryset class to extend from
(``django.db.models.query.QuerySet`` by default).
:keyword manager_cls: The base manager class to extend from
(``django.db.models.manager.Manager`` by default).
'''
# collect separately the mixin classes and methods
bases = [kwds.get('queryset_cls', QuerySet)]
methods = {}
for mixin in mixins:
if isinstance(mixin, (ClassType, type)):
bases.append(mixin)
else:
try: methods[mixin.__name__] = mixin
except AttributeError:
raise TypeError('Mixin must be class or function, not %s' %
mixin.__class__)
# create the QuerySet subclass
id = hash(mixins + tuple(kwds.iteritems()))
new_queryset_cls = type('Queryset_%d' % id, tuple(bases), methods)
# create the Manager subclass
bases[0] = manager_cls = kwds.get('manager_cls', Manager)
new_manager_cls = type('Manager_%d' % id, tuple(bases), methods)
# and finally override new manager's get_query_set
super_get_query_set = manager_cls.get_query_set
def get_query_set(self):
# first honor the super manager's get_query_set
qs = super_get_query_set(self)
# and then try to bless the returned queryset by reassigning it to the
# newly created Queryset class, though this may not be feasible
if not issubclass(new_queryset_cls, qs.__class__):
raise TypeError('QuerySet subclass conflict: cannot determine a '
'unique class for queryset instance')
qs.__class__ = new_queryset_cls
return qs
new_manager_cls.get_query_set = get_query_set
return new_manager_cls()
#==== example ==================================================================
from datetime import datetime
from django.db import models
from django.contrib.auth.models import User
class AuthorMixin(object):
def by_author(self, user):
return self.filter(user=user)
class PublishedMixin(object):
def published(self):
return self.filter(published__lte=datetime.now())
def unpublished(self):
return self.filter(published__gte=datetime.now())
class CustomManager(Manager):
def get_query_set(self):
return super(CustomManager, self).get_query_set().order_by('-published')
class Post(models.Model):
user = models.ForeignKey(User)
published = models.DateTimeField()
objects = manager_from(AuthorMixin, PublishedMixin, unpublished,
manager_cls=CustomManager)
print Post.objects.by_author(user=12).unpublished().query
Comments
Brilliant! I find snippets like this easier to use if they are incorporated in a pip-installable Python project: have you released this code in any such project? If not, would you be open to its (fully credited) inclusion in django-model-utils (http://bitbucket.org/carljm/django-model-utils)?
#
@carljm, no it's not released anywhere; feel free to include it in your project with proper attribution.
#
2010-07-22: Fixed bug that was effectively ignoring the
get_query_setof a passed custom manager. Now the parentget_query_setis honored, unless there is a conflict between the type of the returned queryset and the dynamically generated QuerySet subclass, in which case a TypeError is raised.#
Indentation of lines 67 & 68 needs a tab to the right?
#
Sorry, please ignore my comment above.
It's clever how you can pass in a function or a class :-)
#
@gsakkis: thanks, added
#
Perancis memiliki anggaran dunia terbesar kelima nominal militer, [13] serta (dalam hal personil) militer terbesar di Uni Eropa, [rujukan?] Kekuatan deployable terbesar ketiga di NATO, dan militer-26 terbesar di dunia. Perancis juga memiliki stockpile terbesar ketiga senjata nuklir di dunia [14] - dengan sekitar 300 hulu ledak aktif sejak tips cepat hamil 25 Mei 2010 -. Dan dunia terbesar kedua diplomatik korps (di belakang Amerika Serikat) [15] Perancis adalah anggota pendiri PBB, salah satu dari lima anggota tetap Dewan Keamanan PBB, dan anggota Francophonie, teknisi komputer G8, G20, NATO, OECD, WTO, dan Uni Latin. Ini juga merupakan pendiri dan negara anggota terkemuka dari Uni Eropa dan negara Uni Eropa kursus bahasa inggris murah terbesar berdasarkan wilayah. [16] Pada 2013, Prancis tercatat 20 cara mendapatkan uang dari internet pada Indeks Pembangunan Manusia dan, pada tahun 2010, 24 pada Indeks Persepsi Korupsi.
#