Django模型继承和管理系统

6

我希望建立一个系统来管理页面中各种类型的内容。例如,页面可能包含文本内容、超链接内容、视频内容等。

在我的建模代码中,我有一个基类:

class ContentItem(models.Model):
    title = models.CharField(max_length=1000)
    page_order = models.IntegerField()
    last_update_date = models.DateTimeField(default=datetime.now())

    class Meta:
      abstract = True
      ordering = ['page_order', 'last_update_date', 'title']

这是所有内容项的基类。页面顺序控制它在页面上的位置,例如page_order = 0的项应该在页面顶部。接下来我定义了一些从这个基类继承的具体内容模型。

class LinkContent(ContentItem):
  url = models.URLField()
  link_text = models.CharField(max_lenth=1000)

class TextContent(ContentItem):
 text = models.CharField()


class VideoContent(ContentItem):
      title = models.CharField()
      video_file = models.FieldField(upload_to = 'videos')

可能会有更多这样的内容类型。然后,我将定义一个页面模型,该模型由所有不同的内容类型组成。理想情况下,我可以基于基础类型将所有类型放在一个关系中。因此,在这个关系中,您将拥有LinkContents、TextContents和VideoContents的混合体。它们将按照page_order进行排序,以确定在呈现模板时它们在页面上的顺序。

class Page(models.Model):
  contents = models.ManyToManyField(ContentItem)
  title = models.CharField()

有没有办法让这样的方案生效?或者在一个关系中使用不同类型的模型是否存在问题?我知道从面向对象编程的角度来看,这是一个很好的解决方案,基本上是利用多态性来实现优势,但我不确定它在数据库层面上是否有意义。

我需要像这样的东西吗:

class Page(models.Model):
  video_contents = models.ManyToManyField(VideoContent)
  link_contents = models.ManyToManyField(LinkContent)
  text_contents = models.ManyToManyField(TextContent)
  title = models.CharField()

我知道这个方法可以行得通,但是我确定对象在页面上的位置会变得更加困难。我需要遍历所有内容关系,按照页面顺序进行排序,然后进行渲染。

我认为在两种情况下,我都想在基类上声明一个render()方法,以便每种特定的内容类型都可以继承它。这样,如果我有一个ContentItems列表,我可以使用鸭子类型来渲染它们,而不用担心它们的具体类型。

我的最后一个问题是,如何使管理员与此相适应?如何轻松地查看组成页面的所有ContentItems,以便通过更改page_order轻松移动它们?

感谢您阅读这篇文章,如果您需要更多信息,请让我知道。

1个回答

3

这是一种很好的方法。不幸的是,Django的ORM处理模型继承的方式并不如您所希望的那样顺畅。page.contents将包含Content对象的查询集。如果您想访问子类型,则需要创建一些降低内容对象的方式。问题在于,这需要每个对象进行一次查询,这可能会迅速失控。这篇博客文章描述了一种使用select_related()在后台获取混合子类型的技巧。


1
谢谢@jcdyer。那是非常有帮助的信息。不过,我仍然不清楚如何在管理员界面中使它工作。理想情况下,我希望有一种列出页面内容并根据特定类别显示相应管理表单的方法。例如,如果页面中的 contents 属性有2个 LinkContents 和 1 个 TextContent,我希望前两个可以使用 Link 表单进行编辑,而其他一个可以使用文本表单进行编辑。有没有一种简单的方法可以做到这样?我已经进行了很多管理自定义,但从未见过这样的东西。 - Jon

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