使用集成查询集的子类化Django模型

7

就像这个问题中的情况一样,但我希望能够有查询集返回混合对象:

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

我发现不能仅将Product.Meta.abstract设置为true,或者将不同对象的查询集合并到一起。但这些都是共同类的子类,所以如果我将它们的超类保留为非抽象类,只要我能让其管理器返回正确类的对象,就应该很满意了。Django中的查询代码执行其功能,只需调用Product()。听起来很容易,但当我重写Product.__new__时,它会崩溃,我猜测是由于Model中的__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__函数,但都无济于事。这是什么原因?我必须学习Django元类才能解决问题吗?还是有更好的方法实现我的目标?

1
试图解决这个难题很诱人,但直觉告诉我你在错误地处理。这对于Django ORM来说就像折磨一样。 - keturn
5个回答

4

代码片段链接已损坏。 - freyley

2

1
只需在__new__方法前面加上@staticmethod即可。
@staticmethod
def __new__(cls, *args, **kwargs):
    print args, kwargs
    return super(License, cls).__new__(cls, *args, **kwargs)

1

好的,这个可以运行: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调用<A.__new__>(A_prime, 1),这不匹配,然后就会出错。

因此,解决方案是在定义A_prime之后定义你的__new__

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

现在,当我之前说“这个可行”时,我指的是这个在当前Django SVN版本中与最小对象构造测试用例隔离使用是可行的。我不知道它是否实际上作为模型或在查询集中是否有用。如果你真的在生产代码中使用它,我会在pdxpython上做一个公开的闪电演讲,并让他们嘲笑你,直到你给我们买所有的无麸质披萨。

嘿。好吧,这让我得到了所需的子类行为,但它确实破坏了我的所有关系!我的对象都无法与其他模型相关联。我将进一步研究以查看是否可以修复该方面。 - outofculture


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接