Django模型继承,筛选模型

4
给定以下模型:(不要在意那些文本字段,它们只是为了说明)
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')

根据这些定义,一个内容对象可以与多个基础对象关联,例如,一次采访(=内容对象)可以与音乐家(=Child1对象)、电影导演(=Child2对象)等关联。
现在,我的问题是: 是否可以根据 aso_items 字段指向的模型来过滤内容对象? 例如:假设我想要一个 Queryset,其中包含所有与 Child1 对象的特定对象相关联的 Content 对象(例如,与音乐家 Bob Dylan 相关联的所有采访),我该如何实现?
此外,如果我想要一个包含所有与 Child1 对象相关联的 Content 对象的 QuerySet?(例如,所有与音乐家相关联的采访) 这如何改变过滤?
提前感谢 附:我在预览中遇到了一些空格问题,请原谅。
3个回答

7
你应该查看Django文档中有关使用related_name的抽象基类的部分。http://docs.djangoproject.com/en/dev/topics/db/models/#be-careful-with-related-name 引用文档:
如果在ForeignKey或ManyToManyField上使用related_name属性,则必须始终为该字段指定唯一的反向名称。这通常会在抽象基类中引起问题,因为此类的字段包括在每个子类中,并且每次都具有完全相同的属性值(包括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()

如果Content模型不是太抽象,这是一个很好的解决方案。如果Content模型也是一个抽象模型,那么它将不再起作用。(但这是我发布的不同问题) - fvdnabee
好的。如果两者都是抽象的,我认为你需要像Adam建议的那样使用ContentType框架。 - Mark Lavin

2

显然,使用抽象类进行外键关联(或者ManyToMany关联)是不被允许的。

你会遇到以下错误:'AssertionError: ForeignKey cannot define a relation with abstract class Artiest'。

一个可能的解决方案是将基类定义为非抽象类,但这意味着可以实例化基类的模型。这并不是我想要的行为。(毕竟它是一个抽象类)

有人遇到过同样的问题吗?你是如何解决的?还有其他替代方案吗?


1

请查看http://www.djangoproject.com/documentation/models/generic_relations/,其中介绍了通用关系。您的Content模型将与他们的TaggedItem模型匹配,而您的Base模型将与他们的Animal/Vegetable/Mineral模型匹配(其中Child1和Child2进行扩展)。

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

child_contents = childObject.contents.all()

获取模型的所有内容对象:

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

这可能就是我正在寻找的,ContentType框架可以启用通用关系的使用,并在http://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/有详细文档。Django中标准的评论应用程序(django.contrib.comments)使用了这个框架,因此提供了可用的示例代码。我现在正在研究它。 - fvdnabee
我关心性能问题,我们的网站每天大约有11k次点击量,我希望我的解决方案当然是可扩展的。(点击量可能会增加)有人可以对此事提供一些见解吗? 生产服务器将在slicehost的VPS上运行。 - fvdnabee

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接