Django模型继承与管理员系统

6 投票
1 回答
2745 浏览
提问于 2025-04-16 14:07

我正在尝试建立一个系统,用来管理页面中各种类型的内容。比如,一个页面可能有文本内容、超链接内容、视频内容等等。

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

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

我知道这样是可行的,但我确定对象在页面上的位置会变得更难处理。我需要遍历所有内容关系,按 page_order 排序,然后再渲染它们。

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

我最后一个问题是,如何让管理员在这方面配合得更好?我该如何提供一个简单的方法,让他们可以在一个视图中看到构成页面的所有 ContentItems,以便通过更改 page_order 来轻松移动它们?

感谢你阅读这些内容,如果你需要更多信息,请告诉我。

1 个回答

3

这个方法挺不错的。不过,Django的ORM(对象关系映射)在处理模型继承时,可能没有你想象中的那么顺利。page.contents会包含一组Content对象。如果你想访问这些对象的子类型,你需要想办法把内容对象“降级”到具体的子类型。问题是,这样做需要对每个对象进行一次查询,这样很快就会变得很麻烦。这篇博客介绍了一种技巧,可以在一个查询中获取混合的子类型,背后使用了select_related()

撰写回答