Django 1.6 分支中发生了啥影响了 Manager 元类的工作方式?
Posted
技术标签:
【中文标题】Django 1.6 分支中发生了啥影响了 Manager 元类的工作方式?【英文标题】:What happened in the Django 1.6 branch that affected how Manager metaclasses work?Django 1.6 分支中发生了什么影响了 Manager 元类的工作方式? 【发布时间】:2014-02-07 05:53:00 【问题描述】:我有一个小实用模块 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 的 Manager 相关管道中的 1.5 和 1.6 版本之间发生了什么可能导致这种情况?
† – NB,我明白我可以自己解决这个问题,方法是 a) 阅读 Django 源差异的无穷 kLOC 或 b) 在其中一个 bajillion 中完成大致相同的事情其他可能接近概念想法 django-delegate 地址的方式;主要是我对导致此 Manager 元类情况的任何原因感兴趣。谢谢你,我的 Djangonauts 伙伴
【问题讨论】:
【参考方案1】:为了弃用 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.DelegateSupervisor
是 type(django.db.models.manager.Manager)
的子类,而不是 type
。这应该适用于 Django 1.5 和 1.6。我在您的存储库上创建了一个 PR 来解决这个问题。
顺便说一句,您可能想看看Django 1.7 release note。 Django 中内置了一个委托替代方案。
【讨论】:
就是这样!毫无疑问,这是我记得收到的最全面有用和最有帮助的 SO 回复,就像任何问题一样。谢谢!以上是关于Django 1.6 分支中发生了啥影响了 Manager 元类的工作方式?的主要内容,如果未能解决你的问题,请参考以下文章
View.post @Runnable 到底发生了啥 [重复]