与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)
,Top
,super(A, A)
以及上述所有内容并将cls
作为__new__
的第一个参数传递给所有人徒劳无功。为什么这么踢我?我是否必须弄清楚django的元类才能解决这个问题,还是有更好的方法来实现目标?
答案 0 :(得分:4)
基本上你要做的是返回不同的子类,同时查询共享的基类。那就是:你想要叶子类。请查看此代码段以获取解决方案:http://www.djangosnippets.org/snippets/1034/
另外请务必查看关于Django的Contenttypes框架的文档:http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/一开始可能有点令人困惑,但Contenttypes将解决在Django使用非抽象基类时可能遇到的其他问题ORM。
答案 1 :(得分:2)
你想要其中一个:
http://code.google.com/p/django-polymorphic-models/
https://github.com/bconstantin/django_polymorphic
有缺点,即额外查询。
答案 2 :(得分: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)
,它不匹配,并且会爆炸。
因此,解决方案是在定义 __new__
后定义您的A_prime
。
也许这是django.db.models.base.ModelBase.add_to_class
中的一个错误,也许这是Python中的一个错误,我不知道。
现在,当我之前说“这个有用”时,我的意思是这与当前SVN版本的Django 中的最小对象构造测试用例隔离开来。我不知道它是否真的作为模型工作或在QuerySet中有用。如果你真的在生产代码中使用它,我将为pdxpython做一个公开的闪电谈话,让他们嘲笑你,直到你给我们所有的无麸质比萨饼。
答案 3 :(得分:1)
只需在__new__
方法之前粘贴@staticmethod。
@staticmethod
def __new__(cls, *args, **kwargs):
print args, kwargs
return super(License, cls).__new__(cls, *args, **kwargs)
答案 4 :(得分:1)