模型多态性与模型 - 视图分离

时间:2012-07-12 00:03:10

标签: django model-view-controller design-patterns database-design

我在制作我的Django应用程序时遇到了各种困境,但我认为我遇到的问题通常可能适用于MVC模式。我正在建立一个Question模型,可用于构建测验或问卷调查。 Question基类将是一个简单的免费回复问题。我想支持不同类型的问题,例如多选问题或滑动比例问题,这些问题将是Question基类的子类,其中添加了额外的字段,例如可能的选择数组。我希望能够扩展我的问题模型以支持将来更多类型的问题,为此我可以依赖多态并在模型层和视图层之间传递Question类型的对象Question的所有子类。

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

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

1 个答案:

答案 0 :(得分:0)

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

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

BaseQuestion <- FreeQuestion, 
                MultipleChoiceQuestion, 
                SlidingScaleQuestion etc.

然后你可以构建一个BaseQuestionView知道如何显示BaseQuestion(例如渲染问题字符串,设置它的样式和不是什么)并使用相同的原理构造:

BaseQuestionView <- FreeQuestionView, 
                    MultipleChoiceQuestionView, 
                    SlidingScaleQuestionView

您可以使BaseQuestionView抽象为从数据库中提取所有BaseQuestion模型实例,并调用在每个render_questionFreeQuestionView中实现的抽象MultipleChoiceQuestionView方法, SlidingScaleQuestionView个子类。因此FreeQuestionView知道它使用FreeQuestion模型,并且只实现如何为答案(文本字段)呈现小部件。 MultipleChoiceQuestionView只会实现如何渲染无线电盒等。

换句话说,它几乎就是你在第一种情况下呈现的内容,除了渲染实现位于View类而不是Model类中。

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


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

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

据我所知,Django没有自动方式在继承的模型和继承的视图之间建立关联,你必须自己制作映射。

也许最简单的方法是显式请求所有与FreeQuestions,MultipleChoiceQuestions等相关的初始Question QuerySet匹配的实例,然后将它们放入列表中,然后再将其提供给主渲染器,然后再渲染{{1}从mixin中找到渲染器方法。或者,您可以将问题类型保留在基类中,以避免必须处理类映射并让DB帮助您。

但是,通常您不希望模型行为针对同一个类动态更改(这是您使用BaseQuestion实际执行的操作)。在设计REST时尤其如此,因为您希望显式URL映射到显式具体而非抽象类型。

相关问题