假设我有一个父类(ThingsThatMigrate)和两个孩子(Coconut和Swallow)。现在让我们说我有一个ThingsThatMigrate对象。我怎样才能确定它实际上是椰子还是燕子?一旦这样做了,我怎么才能到达椰子或燕子对象?
答案 0 :(得分:7)
Django并不提供开箱即用的模型多态性。您尝试实现的最简单方法是在其中存储新对象的内容类型。有一个名为django-polymorphic-models的简单通用应用程序,它为您提供此功能 - 另外还有一个downcast
方法,它将返回子对象!
答案 1 :(得分:2)
具体或抽象继承?如果具体:
>>> things = ThingsThatMigrate.objects.all().select_related('coconut', 'swallow')
>>> for thing in things:
... thing = thing.coconut or thing.swallow or thing
... print thing
可以使用django-model-utils InheritanceManager
自动执行此操作(然后您无需担心select_related
或手动列出所有可能的子类)。由另一位Django核心开发人员维护。
答案 2 :(得分:0)
它不是特别漂亮或高效,但我能想到实现这一点而不将子类元数据存储在数据库中的最佳方式(如django-polymorphic-models那样)将是child()
方法ThingsThatMigrate
{1}}模型类:
from django.core.exceptions import ObjectDoesNotExist
def child(self):
for subclass in self.__class__.__subclasses__():
try:
return getattr(self, subclass.__name__.lower())
except (AttributeError, ObjectDoesNotExist):
continue
答案 3 :(得分:0)
在我使用的Django CMS上(Merengue http://www.merengueproject.org/),我们存储了“classname”属性,该属性存储了对象的真实类。
为了获得真实实例,我们使用了以下方法:
def get_real_instance(self):
""" get object child instance """
def get_subclasses(cls):
subclasses = cls.__subclasses__()
result = []
for subclass in subclasses:
if not subclass._meta.abstract:
result.append(subclass)
else:
result += get_subclasses(subclass)
return result
if hasattr(self, '_real_instance'): # try looking in our cache
return self._real_instance
subclasses = get_subclasses(self.__class__)
if not subclasses: # already real_instance
self._real_instance = getattr(self, self.class_name, self)
return self._real_instance
else:
subclasses_names = [cls.__name__.lower() for cls in subclasses]
for subcls_name in subclasses_names:
if hasattr(self, subcls_name):
return getattr(self, subcls_name, self).get_real_instance()
return self
这个函数的重要之处在于,如果类是抽象的,它会记住,这会改变逻辑。
答案 4 :(得分:0)
正如DrMeer建议的那样,我强烈推荐django-model-utils(现在托管在bitbucket上)。我不确定它是否足够令人信服 让代码示例证明:
>>> ThingsThatMigrate.objects.all().select_subclasses()
Coconut, Coconut, Swallow, Coconut, ThingsThatMigrate
在您的父模型中需要一行objects = InheritanceManager()
。
答案 5 :(得分:-2)
来自the docs:
如果您的
Place
也是Restaurant
,则可以使用小写版本的Place
从Restaurant
对象转到{{1}}对象型号名称......