模型/视图之间的分离旨在将表示与数据分离。您对多态模型层次结构的初始描述Question
确实是一种有效的方法。
您在这里真正想做的是考虑使用 Django 的模型继承来处理数据层次结构,即:
BaseQuestion <- FreeQuestion,
MultipleChoiceQuestion,
SlidingScaleQuestion etc.
然后,您可以构建一个BaseQuestionView
知道如何显示的BaseQuestion
(例如渲染问题字符串、设置样式以及其他)并使用相同的原理构造:
BaseQuestionView <- FreeQuestionView,
MultipleChoiceQuestionView,
SlidingScaleQuestionView
您可以将 BaseQuestionView 抽象为BaseQuestion
从数据库中提取所有模型实例并调用在每个子类中render_question
实现的抽象方法。因此知道它与模型一起工作,并且只实现如何为答案(文本字段)呈现小部件。只会实现如何渲染单选框等。FreeQuestionView
MultipleChoiceQuestionView
SlidingScaleQuestionView
FreeQuestionView
FreeQuestion
MultipleChoiceQuestionView
换句话说,它几乎与您在第一个案例中呈现的内容完全相同,只是渲染实现位于 View 类而不是 Model 类中。
当您想以不同方式渲染同一类对象时,可以应用相同的原则。
使用模型继承,您可以使用点符号访问基本实例的任何子类,即:question.freequestion
。这将返回给您与基本实例关联的 FreeQuestion 实例,或者Question.DoesNotExist
如果那不是它的类,则引发。
使用基于类的视图,您可以添加可以根据天气以不同方式呈现您的问题的 Mixins,这是一个 FreeQuestion、MultipleChoiceQuestion,使用 python 的 MRO 模式,或者您可以将它们子类化。
据我所知,Django 没有自动的方法来在继承的模型和继承的视图之间建立关联,您必须自己进行映射。
也许最简单的方法是显式请求与您的初始 Question QuerySet 相关的所有实例,分别与 FreeQuestions、MultipleChoiceQuestions 等相关,并将它们投射到列表中,然后再将其提供给您的主渲染器,然后通过 amap[question.__class__]
从混音。或者,您可以将问题类型保留在基类中,以避免处理类映射并让数据库在这方面为您提供帮助。
但是,通常您不希望您的模型行为为同一个类动态更改(这就是您对 BaseQuestion 所做的有效操作)。在考虑 REST 进行设计时尤其如此,因为您希望显式 URL 映射到显式具体而非抽象类型。