Django 1.6分支中发生了什么影响了Manager元类的工作方式?

时间:2014-01-17 18:58:23

标签: python django django-queryset metaclass python-decorators

我有一个小实用程序模块django-delegate,它允许您在QuerySet子类上定义方法,然后通过@delegate装饰将这些方法定义“委托”到相应的Manager子类。

看起来像这样,如果我可以引用我自己的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()

...该设置允许在模型的管理器引用上进行方法链接,而不需要任何运行时调度,如此

>>> SomeModel.objects.custom_query().another_custom_query()

在幕后,该模块通过在Manager子类DelegateManager上使用元类工作 - 并且在Django变为1.6之前一直没有问题。现在,当使用使用DelegateManager的模型导入应用程序时,我得到其中一个令人发狂的深奥元类相关的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: Django与管理器相关的管道版本1.5和1.6之间发生的事情可能导致这种情况发生?


- 注意,我明白我可以通过以下方式解决这个问题:a)阅读Django源差异的无穷无尽的kLOC,或者b)在其中一个中完成大致相同的事情其他方式可以接近django-delegate地址的概念性想法;主要是我对导致这个Manager元类情况的任何内容感兴趣。谢谢你,我的同伴Djangonauts

1 个答案:

答案 0 :(得分:3)

为了弃用get_query_set而使用get_queryset#15363),django.db.models.manager.Manager现在是django.db.models.manager.RenameManagerMethods的实例,django.utils.deprecation.RenameMethodsBase的子类}}

由于delegate.DelegateSupervisor不是django.db.models.manager.RenameManagerMethods的(非严格)子类,因此Python无法解析正确的delegate.DelegateManager元类。

要解决此问题,您应确保delegate.DelegateSupervisortype(django.db.models.manager.Manager)的子类,而不是type。这适用于Django 1.5和1.6。我在您的存储库上创建了一个PR以解决此问题。

顺便说一下,你可能想看一下Django 1.7 release note。 Django内置了代理替代方案。