Django模型继承与管理员系统
我正在尝试建立一个系统,用来管理页面中各种类型的内容。比如,一个页面可能有文本内容、超链接内容、视频内容等等。
在我的模型代码中,我有一个基础类:
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 个回答
这个方法挺不错的。不过,Django的ORM(对象关系映射)在处理模型继承时,可能没有你想象中的那么顺利。page.contents
会包含一组Content
对象。如果你想访问这些对象的子类型,你需要想办法把内容对象“降级”到具体的子类型。问题是,这样做需要对每个对象进行一次查询,这样很快就会变得很麻烦。这篇博客介绍了一种技巧,可以在一个查询中获取混合的子类型,背后使用了select_related()
。