Django模型继承,过滤模型

时间:2009-09-08 12:07:09

标签: django django-models django-orm

鉴于以下模型:(不要介意TextFields只是为了说明)

class Base(models.Model):
   field1 = models.TextField()

   class Meta:
      abstract=True

class Child1(Base):
   child1_field = models.TextField()

class Child2(Base):
   child2_field = models.TextField()


class Content(models.Model):
    aso_items = models.ManyToManyField('Base')

根据这些定义,Content对象可以与多个Base对象相关联,例如。面试(=内容对象)可以与音乐家(= Child1对象),电影导演(= Child2)等链接。

现在,对于我的问题: 是否可以根据aso_items字段指向的模型过滤Content对象? 例如:假设我想要一个Queryset,其中包含与Child1的特定对象相关联的所有Content对象(例如,与音乐家Bob Dylan相关的所有访谈),我该如何实现?

此外,如果我想要一个包含与Child1对象关联的所有Content对象的QuerySet,那该怎么办?(例如,所有与音乐家相关的访谈) 这如何改变过滤?

提前致谢 ps:我在预览中遇到了一些空白问题,请原谅我

3 个答案:

答案 0 :(得分:7)

您应该检查Django文档中有关使用related_name进行抽象基类的部分。 http://docs.djangoproject.com/en/dev/topics/db/models/#be-careful-with-related-name

引用文档:

  

如果您使用related_name   ForeignKey或的属性   ManyToManyField,你必须永远   为。指定唯一的反向名称   领域。这通常会导致   抽象基类中的问题,   因为这个类的字段是   包括在每个孩子中   类,具有完全相同的值   对于属性(包括   每次related_name)。

     

解决这个问题,当你   在摘要中使用related_name   基类(仅),名称的一部分   应该是字符串%(class)s。这个   被替换为低级的名称   使用该字段的子类   因为每个班级都有不同   名称,每个相关名称将最终   与众不同。

使用此信息,我建议将m2m字段移动到Base类:

class Content(models.Model):
   # Add remaining fields for Content 
   pass

class Base(models.Model):
   field1 = models.TextField()
   items = models.ManyToManyField(Content,related_name="%(class)s_related")

   class Meta:
      abstract=True

class Child1(Base):
   child1_field = models.TextField()

class Child2(Base):
   child2_field = models.TextField()

答案 1 :(得分:2)

显然不允许使用带抽象类的ForeignKey关系(或者说很多事情)。 我收到以下错误:'AssertionError:ForeignKey无法定义与抽象类Artiest'的关系。

一种可能的解决方案是将基类定义为非抽象类,但这意味着可以实例化基类的模型。这不是我想要的行为。(毕竟它是一个抽象类) 有人遇到同样的问题你是如何解决的?任何替代方案?

答案 2 :(得分:1)

查看通过通用关系的http://www.djangoproject.com/documentation/models/generic_relations/。您的内容模型将匹配其TaggedItem模型,您的Base模型将匹配其动物/蔬菜/矿物模型(Child1和Child2扩展)。

获取单个子项的所有Content对象(假设您将GenericRelation设置为Base中的内容):

child_contents = childObject.contents.all()

获取模型的所有Content对象:

ctype = ContentType.objects.get_for_model(Child1)
all_child_contents = Content.objects.filter(content_type=ctype)