给出以下代码:
class BaseMedium(models.Model):
title = models.CharField(max_length=40)
slug = models.SlugField()
class A(BaseMedium):
url = models.URLField()
class B(BaseMedium):
email = models.EmailField()
我现在想查询每个BaseMedium。
b = BaseMedium.objects.all()
如何在不知道子类类型的情况下打印包括子类字段在内的所有信息?
如果b[0].a
实际上与b[0]
实例相关,则 A
会打印信息,但如果它与B
相关,则会打印DoesNotExist
例外。
这是有道理的,但我希望有一个返回相关对象的公共变量或方法。
也许我的数据库布局不是那么查询,如果是这样我会很高兴你推荐一个更好的布局。
我考虑过使用GenericForeignKey
class Generic(models.Model):
basemedium = models.ForeignKey('BaseMedium')
content_type = models.ForeignKey(ContentType)
object_id = models.PositiveIntegerField()
object = generic.GenericForeignKey('content_type', 'object_id')
但这个解决方案似乎很复杂,我认为你们有更好的解决方案。
答案 0 :(得分:5)
你应该在前一段时间检查解决方案posted by Carl Meyer。它在内部使用ContentType方法,但它非常优雅地封装它。
他还指出了另一种更有效的解决方案,它不需要在数据库中存储aditional字段,但它只适用于直接子类。如果你有几个继承级别,第一个解决方案更好。
答案 1 :(得分:2)
执行此操作的唯一方法是在基础模型上明确存储它的类型。所以在BaseMedium上有一个derived_type
(或其他)字段,并将其设置为save。然后你可以使用get_derived_type
方法:
def get_derived_type(self):
if self.derived_type == 'A':
return self.a
elif self.derived_type == 'B':
return self.b
等等。
答案 2 :(得分:1)
def related_object(self, default_pointer_name='_ptr'):
models = [A,B] #models
object = None
argument = '%s%s' %(self.__class__.__name__.lower(), default_pointer_name)
query = { argument : self}
for model in models:
try:
object = model.objects.get(**query)
except model.DoesNotExist:
pass
else:
return object
if object == None:
raise RelatedObjectException
return object
这是BaseMedium使用的方法。
答案 3 :(得分:0)
这对我有用(使用self.subclass_name_in_lower_case):
在此示例中,子类为TextTreeItem, CategoryTreeItem and KeywordTreeItem
。
class TreeItem(MPTTModel):
parent = TreeForeignKey('self', on_delete=models.CASCADE, verbose_name=_('Parent'),
null=True, blank=True, related_name='%(class)s_related')
objects = CustomTreeManager()
@property
def daughter(self):
try:
return self.texttreeitem
except TreeItem.texttreeitem.RelatedObjectDoesNotExist:
pass
try:
return self.categorytreeitem
except TreeItem.categorytreeitem.RelatedObjectDoesNotExist:
pass
try:
return self.keywordtreeitem
except TreeItem.keywordtreeitem.RelatedObjectDoesNotExist:
return self