如何干我的模特

时间:2014-03-28 16:34:32

标签: django django-models

我正在制作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,并重复我在视图中为问题投票所做的一切。我看了一下模型继承,但如果我声明一个抽象基类并从中继承问题和答案模型,那么我就不能使用外键。那么避免这种重复的最佳方法是什么?

3 个答案:

答案 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)

查看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)

(注释块在本例中是为了便于阅读。)

“但现在我有更多型号!”

是的,但是其中任何一个都没有重复的字段,抽象意味着您有权添加不同的行为 - 例如QuestionVoteAnswerVote(比如说如果出现更好的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)
    ...