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