0

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

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

难道还有第三个解决方案没有我想到的解决方案的缺点吗?或者,这是一个真正困难的问题,哪一个人需要作出困难的决定?

回答

0

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

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

BaseQuestion <- FreeQuestion, 
       MultipleChoiceQuestion, 
       SlidingScaleQuestion etc. 

然后你就可以建立一个BaseQuestionView知道如何显示BaseQuestion(例如渲染问题字符串,它的风格,什么不可以),并使用相同的原理结构:

BaseQuestionView <- FreeQuestionView, 
        MultipleChoiceQuestionView, 
        SlidingScaleQuestionView 

可以使BaseQuestionView抽象,以拉都BaseQuestion模型实例从一个数据库并且调用分别在FreeQuestionView,MultipleChoiceQuestionView,SlidingScaleQuestionView子类中实施的摘要render_question方法。因此FreeQuestionView知道它与FreeQuestion模型一起工作,并且只实现了如何为答案呈现小部件(textfield)。 MultipleChoiceQuestionView只会实现如何渲染收音机等。

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

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


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

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

据我所知,Django没有自动的方式来使继承模型和继承视图之间的关联,你必须自己做映射。

也许最简单的方法是明确请求所有与FreeQuestions,MultipleChoiceQuestions等相关的初始Question QuerySet相匹配的实例,然后将它们投入列表中,然后将它们提交给主渲染器,然后再通过map[question.__class__]查找mixin的渲染器方法。或者,您可以将问题类型保留在基类中,以避免必须处理类映射,并让数据库在这方面为您提供帮助。

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

+0

感谢您的回应,它似乎是一个很好的解决方案。我确实有一个后续:我如何确保'BaseQuestionView'的正确子类与'BaseQuestion'的特定实例相关联?如果每个'BaseQuestion'实例在运行时被实例化,那么当每个问题被实例化时,我会将每个问题与'BaseQuestionView'的正确子类的代理关联起来。但我不确定使用数据库查询填充问题列表的最佳方式是什么。你将如何实施这个协会? – solarein 2012-07-12 02:29:47

+0

查看更新答案。 – astevanovic 2012-07-12 13:06:06