Django模型子类化:通过查询超类来获取子类

时间:2010-06-24 11:23:18

标签: python django django-models

给出以下代码:

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')

但这个解决方案似乎很复杂,我认为你们有更好的解决方案。

4 个答案:

答案 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