我正在制作Q& A网站。目前,我有这样的模型
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 :(得分: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)
...
答案 1 :(得分:0)
您可以将常用字段/功能放在那里(submitter
,detail
等),然后在Question
和Answer
模型中继承它
编辑:
基于其他答案,我更多地看着你的问题,我正在改变我的答案。你现在正处于“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)
(注释块在本例中是为了便于阅读。)
“但现在我有更多型号!”
是的,但是其中任何一个都没有重复的字段,抽象意味着您有权添加不同的行为 - 例如QuestionVote
和AnswerVote
(比如说如果出现更好的AnswerVote
,您希望能够收回Answer
,但又不希望能够收回QuestionVote
s而不需要“这是一个X Y或Z?如果它是Z,则执行此操作“在您编写的每种模型方法中执行此条款。
“它看起来很难看!”
它既可读又明确,这意味着它是beautiful:)
“我想以另一种方式做到这一点!”
没关系,已经有其他好的答案显示了如何做到这一点。这只是我的建议,因为他非常热衷于最佳实践和可读代码。
答案 2 :(得分: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)
...