I have a little utility module, django-delegate, that lets you define methods on a QuerySet subclass and then “delegate” those method definitions to a corresponding Manager subclass, by dint of a @delegate
decoration.
It looks like this, if I can quote from my own README:
from delegate import DelegateManager, delegate
class CustomQuerySet(models.query.QuerySet):
@delegate
def qs_method(self, some_value):
return self.filter(some_param__icontains=some_value)
def dont_delegate_me(self):
return self.filter(some_other_param="something else")
class CustomManager(DelegateManager):
__queryset__ = CustomQuerySet
class SomeModel(models.Model):
objects = CustomManager()
… which that setup allows for method-chaining on the model’s manager reference, without any runtime dispatch vaguery, like so†:
>>> SomeModel.objects.custom_query().another_custom_query()
Behind-the-scenes, the module works by using a metaclass on the Manager subclass, DelegateManager – and that worked without issue until Django turned 1.6. Now, when importing an app with models that use a DelegateManager, I get one of these maddeningly esoteric metaclass-related showstopper TypeErrors:
>>> from tika import models as tika
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/Users/fish/Praxa/TESSAR/instance/tika/models.py", line 4, in <module>
from delegate import DelegateManager, delegate
File "/Users/fish/Praxa/TESSAR/local/lib/python2.7/site-packages/delegate/__init__.py", line 108, in <module>
class DelegateManager(models.Manager):
File "/Users/fish/Praxa/TESSAR/local/lib/python2.7/site-packages/delegate/__init__.py", line 105, in __new__
cls, name, bases, attrs)
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
>>>
TL,DR: what happened between versions 1.5 and 1.6 in Django’s Manager-related plumbing that could cause this?
† – N.B., I do understand I could solve this myself by either a) reading through endless kLOCs of Django source diffs or b) accomplishing roughly the same thing in one of the bajillion other ways that one could possibly approach the notional idea django-delegate addresses; mainly I am interested in whatever is causing this Manager metaclass situation, tho. Thank you, my fellow Djangonauts