0

我在制作 Django 应用程序时遇到了各种困境,但我认为我遇到的问题可能普遍适用于 MVC 模式。我正在制作一个Question可用于构建测验或问卷的模型。基Question类将是一个简单的免费回答问题。我想支持不同类型的问题,例如多项选择题或滑动比例问题,这些将是Question基类的子类,并添加了额外的字段,例如一系列可能的选择。我希望能够扩展我的问题模型以在将来支持更多类型的问题,为此我可以依赖多态性并Question在模型层和视图层之间为Question.

我遇到的问题是视图必须知道它收到的问题类型才能呈现它。如果它得到一个多项选择问题,它需要绘制单选小部件等。所以现在如果我用更多类型的问题扩展我的模型,我必须将它添加到模型和视图层。这似乎违背了多态性的观点,因为接收Question对象的视图总是必须知道接收到的问题的子类类型。我可以通过将呈现问题的责任委托给模型来解决这个问题。如果Question模型有一个名为的虚函数render_question()如果它的子类覆盖,那么视图层可以调用该函数来获取正确的 HTML 来输出,而不必担心问题的类型。但是现在我遇到了将 HTML 渲染代码与模型绑定的问题。

是否有第三种解决方案没有我想到的解决方案的任何一个缺点?或者这真的是一个必须做出艰难决定的困境吗?

4

1 回答 1

0

模型/视图之间的分离旨在将表示与数据分离。您对多态模型层次结构的初始描述Question确实是一种有效的方法。

您在这里真正想做的是考虑使用 Django 的模型继承来处理数据层次结构,即:

BaseQuestion <- FreeQuestion, 
                MultipleChoiceQuestion, 
                SlidingScaleQuestion etc.

然后,您可以构建一个BaseQuestionView知道如何显示的BaseQuestion(例如渲染问题字符串、设置样式以及其他)并使用相同的原理构造:

BaseQuestionView <- FreeQuestionView, 
                    MultipleChoiceQuestionView, 
                    SlidingScaleQuestionView

您可以将 BaseQuestionView 抽象为BaseQuestion从数据库中提取所有模型实例并调用在每个子类中render_question实现的抽象方法。因此知道它与模型一起工作,并且只实现如何为答案(文本字段)呈现小部件。只会实现如何渲染单选框等。FreeQuestionViewMultipleChoiceQuestionViewSlidingScaleQuestionViewFreeQuestionViewFreeQuestionMultipleChoiceQuestionView

换句话说,它几乎与您在第一个案例中呈现的内容完全相同,只是渲染实现位于 View 类而不是 Model 类中。

当您想以不同方式渲染同一类对象时,可以应用相同的原则。


使用模型继承,您可以使用点符号访问基本实例的任何子类,即:question.freequestion。这将返回给您与基本实例关联的 FreeQuestion 实例,或者Question.DoesNotExist如果那不是它的类,则引发。

使用基于类的视图,您可以添加可以根据天气以不同方式呈现您的问题的 Mixins,这是一个 FreeQuestion、MultipleChoiceQuestion,使用 python 的 MRO 模式,或者您可以将它们子类化。

据我所知,Django 没有自动的方法来在继承的模型和继承的视图之间建立关联,您必须自己进行映射。

也许最简单的方法是显式请求与您的初始 Question QuerySet 相关的所有实例,分别与 FreeQuestions、MultipleChoiceQuestions 等相关,并将它们投射到列表中,然后再将其提供给您的主渲染器,然后通过 amap[question.__class__]从混音。或者,您可以将问题类型保留在基类中,以避免处理类映射并让数据库在这方面为您提供帮助。

但是,通常您不希望您的模型行为为同一个类动态更改(这就是您对 BaseQuestion 所做的有效操作)。在考虑 REST 进行设计时尤其如此,因为您希望显式 URL 映射到显式具体而非抽象类型。

于 2012-07-12T00:25:19.027 回答