2014-03-28 34 views
1

我是一個製作Q &的網站。目前,我有這樣的模型如何烘乾我的模特

class Question(models.Model): 
    title = models.CharField(max_length=150) 
    detail = models.TextField() 
    submitter = models.ForeignKey(User) 
    date_added = models.DateTimeField(auto_now_add = True) 
    ...# some additional fields such as tags 

class Answer(models.Model): 
    detail = models.TextField() 
    submitter = models.ForeignKey(User) 
    date_added = models.DateTimeField(auto_now_add = True) 
    ... 

class QuestionVote(models.Model): 
    voter = models.ForeignKey(User) 
    question = models.ForeignKey(Question) 

#replicating what I did for QuestionVote 
class AnswerVote(models.Model): 
     voter = models.ForeignKey(User) 
     question = models.ForeignKey(Question) 

問題和答案模型是一樣的,除了標題和標籤。要爲Answers添加投票功能,我必須將QuestionVote模型複製爲AnswerVote,並重復我在視圖中爲問題投票所做的所有操作。我看了一下模型繼承,但如果我聲明一個抽象基類並繼承問題和答案模型,那麼我不能使用外鍵。那麼避免這種重複的最佳方法是什麼?

+0

@誰指出了這一點,我有正確的複製粘貼錯誤 – yayu

回答

2

您可以使用一個一對一關係的其他周圍方式:

class Vote(models.Model): 
    voter = models.ForeignKey(User) 
    ...# some additional fields 

class Question(models.Model): 
    title = models.CharField(max_length=150) 
    detail = models.TextField() 
    submitter = models.ForeignKey(User) 
    date_added = models.DateTimeField(auto_now_add = True) 
    vote = models.OneToOneField(Vote) 
    ...# some additional fields such as tags 

class Answer(models.Model): 
    detail = models.TextField() 
    submitter = models.ForeignKey(User) 
    date_added = models.DateTimeField(auto_now_add = True) 
    vote = models.OneToOneField(Vote) 
    ... 
+0

我最喜歡這種方法。通過這種方式,我也可以使用繼承,在這種情況下,外鍵將繼承模型。我認爲應該起作用。 – yayu

+0

除非我錯過了一些東西,否則這會給你留下一個「答案」/「問題」的「投票」?這是所需的功能?我以爲你想讓多個人能夠在「答案」上投票等 – ptr

0

看一看abstract base classes

您可以把常用的領域/功能在裏面(submitterdetail等),然後在你的QuestionAnswer車型繼承它

編輯:

根據其他答案和我看你的問題多一點我改變我的答案。您目前正走在「DRY」和「良好的可讀性/可維護性」之間,不同的開發人員會在不同的網站上走下坡路,所以您可能只需要選擇一個您最喜歡的那個。

關於這一點,這裏就是我會一五一十地出來:

############################## 
# Question and Answer Models # 
############################## 

class QuestionAnswerBase(models.Model): # Choose a better name :) 
    detail = models.TextField() 
    submitter = models.ForeignKey(User) 
    date_added = models.DateTimeField(auto_now_add = True) 
    ... # More common fields here 

    class Meta: 
     abstract = True 


class Question(QuestionAnswerBase): 
    title = models.CharField(max_length=150) 
    ...# some additional fields such as tags etc 


class Answer(QuestionAnswerBase): 
    ... # No extra fields needed but you'll prob want a custom __unicode__ method etc 


############### 
# Vote Models # 
############### 

class VoteBase(models.Model): 
    voter = models.ForeignKey(User) 
    ... # Other shared fields etc 

    class Meta: 
     abstract = True 

class AnswerVote(VoteBase): 
    answer = models.ForeignKey(Answer) 


class QuestionVote(VoteBase): 
    question = models.ForeignKey(Question) 

(註釋塊是在這種情況下的可讀性。)

「但現在我有更多的車型!」

是你做的,但也有其中的任何沒有重複領域,抽象意味着你必須添加不同的行爲TO-的示例 - 一個QuestionVoteAnswerVote電源(說你想要的能力如果更好的Answer出現,請收回AnswerVote s,但不希望能夠收回QuestionVote s),而不需要有「這是X是Y還是Z?如果是Z是否這樣做」你寫的每種模型方法。

「看起來很醜!

它的讀取和明確的,這意味着它beautiful :)

「我想要做的另一種方式!」

這很好,現在已經有其他好的答案顯示如何做到這一點。這只是我的建議,因爲對最佳實踐和可讀代碼非常熱衷的人。

+1

但是,您不能將外鍵指向抽象類,因爲抽象類沒有與它們相關的表。 – Selcuk

+0

@Selcuk你是對的,我誤解了要求。雖然默認情況下無法完成,但有很好的django軟件包,允許DRYer模型繼承+外鍵關係,[django-polymorphic](https://django-polymorphic.readthedocs.org/en/最新/ index.html)爲例。雖然這種情況可能會過度。 – ptr

+0

更新了我的答案 – ptr

0

我個人覺得DRY很重要,所以我願意犧牲一些優雅來實現它。例如,在這種情況下,我可能做到這一點:

class QuestionOrAnswer(models.Model): 
    is_question = models.BooleanField() 
    title = models.CharField(max_length=150) 
    detail = models.TextField() 
    submitter = models.ForeignKey(User) 
    date_added = models.DateTimeField(auto_now_add = True) 
    question_specific_field = ... 

    def clean(self): 
     # Make sure that question_specific_field is set only if is_question is true. 

class Vote(models.Model): 
    target = models.ForeignKey(QuestionOrAnswer) 
    ... 
+1

如果Answer有一個外鍵給問題(它實際上應該)會發生什麼? – Selcuk

+0

您可以使用自引用外鍵:question = models.ForeignKey('self')。請參閱http://stackoverflow.com/questions/15285626/django-self-referential-foreign-key – DavidM