【问题标题】:Subclassed django models with integrated querysets具有集成查询集的子类 django 模型
【发布时间】:2011-02-02 06:50:09
【问题描述】:

this question 类似,但我希望能够拥有返回混合对象主体的查询集:

>>> Product.objects.all()
[<SimpleProduct: ...>, <OtherProduct: ...>, <BlueProduct: ...>, ...]

我发现我不能只将 Product.Meta.abstract 设置为 true 或将不同对象的查询集或在一起。很好,但是这些都是公共类的子类,所以如果我将它们的超类保留为非抽象类,我应该很高兴,只要我能让它的管理器返回正确类的对象。 django 中的查询代码完成了它的工作,只是调用 Product()。听起来很简单,除了当我覆盖 Product.__new__ 时它会爆炸,我猜是因为模型中的 __metaclass__... 这是非 django 代码,它的行为与我想要的差不多:

class Top(object):
    _counter = 0
    def __init__(self, arg):
        Top._counter += 1
        print "Top#__init__(%s) called %d times" % (arg, Top._counter)
class A(Top):
    def __new__(cls, *args, **kwargs):
        if cls is A and len(args) > 0:
            if args[0] is B.fav:
                return B(*args, **kwargs)
            elif args[0] is C.fav:
                return C(*args, **kwargs)
            else:
                print "PRETENDING TO BE ABSTRACT"
                return None # or raise?
        else:
            return super(A).__new__(cls, *args, **kwargs)
class B(A):
    fav = 1
class C(A):
    fav = 2
A(0) # => None
A(1) # => <B object>
A(2) # => <C object>

但是如果我从django.db.models.Model 继承而不是object 则失败:

File "/home/martin/beehive/apps/hello_world/models.py", line 50, in <module>
    A(0)
TypeError: unbound method __new__() must be called with A instance as first argument (got ModelBase instance instead)

这是一个非常糟糕的回溯;我也无法在调试器中进入我的__new__ 代码框架。我已经尝试过super(A, cls)Topsuper(A, A) 以及以上所有方法,并结合将cls 作为__new__ 的第一个参数传递给__new__,但都无济于事。为什么这踢我这么狠?我是否必须弄清楚 django 的元类才能解决此问题,还是有更好的方法来实现我的目标?

【问题讨论】:

  • 试图解开谜题很诱人,但直觉告诉我你做错了。这对 Django 可怜的小 ORM 来说简直就是折磨。

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


【解决方案1】:
【解决方案2】:

【讨论】:

    【解决方案3】:

    只需在__new__ 方法之前粘贴@staticmethod。

    @staticmethod
    def __new__(cls, *args, **kwargs):
        print args, kwargs
        return super(License, cls).__new__(cls, *args, **kwargs)
    

    【讨论】:

      【解决方案4】:

      基本上,您要做的是返回不同的子类,同时查询共享基类。那就是:你想要叶子类。检查此 sn-p 以获得解决方案:http://www.djangosnippets.org/snippets/1034/

      还请务必查看有关 Django 的 Contenttypes 框架的文档:http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/ 一开始可能有点令人困惑,但 Contenttypes 将解决您在使用 Django 的 ORM 的非抽象基类时可能会遇到的其他问题。

      【讨论】:

      • sn-p 链接已损坏。
      【解决方案5】:

      好的,这行得通:https://gist.github.com/348872

      棘手的是这个。

      class A(Top):
          pass
      
      def newA(cls, *args, **kwargs):
          # [all that code you wrote for A.__new__]
      
      A.__new__ = staticmethod(newA)
      

      现在,我可能不太了解 Python 如何绑定 __new__,但它的要点是:django 的 ModelBase 元类创建一个新的类对象,而不是使用传入的类对象到它的__new__;打电话给A_prime。然后它将您在A 的类定义中拥有的所有属性粘贴到A_prime,但__new__ 没有正确重新绑定。

      那么当你评估A(1)时,A这里其实是A_prime,python调用&lt;A.__new__&gt;(A_prime, 1),不匹配,就爆炸了。

      所以解决方案是定义你的__new__ A_prime 被定义之后。

      也许这是django.db.models.base.ModelBase.add_to_class的一个bug,也许是Python的一个bug,我不知道。

      现在,当我之前说“这有效”时,我的意思是这与当前 SVN 版本的 Django 中的最小对象构造测试用例隔离工作。我不知道它实际上是作为模型工作还是在 QuerySet 中有用。如果你真的在生产代码中使用它,我会公开闪电般地讨论 pdxpython 并让他们嘲笑你,直到你给我们买所有无麸质披萨。

      【讨论】:

      • 嘿。好吧,这让我得到了所需的子类化行为,但是哦,它有没有破坏我所有的关系!我的所有对象都不能与其他模型相关联。我会进一步研究它,看看我是否可以解决这个问题。
      猜你喜欢
      • 2013-07-30
      • 2012-12-15
      • 1970-01-01
      • 2018-10-06
      • 2018-12-20
      • 2010-09-26
      • 2020-11-14
      • 1970-01-01
      • 2011-10-25
      相关资源
      最近更新 更多