Search code examples
pythondjangomodels

How to make relation between one model to another two models


I am creating simple forum site using Django framework, and I've created comment model, at this moment my comment model has OneToOne relation with Post, it means that every moment belong to specific post, but there is also another feature that I want to provide. Every comment model should has possibility to be related to Post object OR to Answer model. Answer model it is just as in Stack Overflow, you add a Post and another user can add an answer to it. I want to mention that answer is too related with Post with OneToOne relation I think it will be sufficient and dosen't need edition. Summarizing: How to allow adding comments to Post object or Answer object? Also I want to say that I was considering creating two comments models, namely PostComment, and AnswerComment but I've got a conclusion that is really bad solution.

class Post(models.Model):
    subject = models.CharField(max_length=100)
    description = models.TextField(null=True)
    section = models.ForeignKey(Section, on_delete=models.CASCADE, null=True)
    author = models.ForeignKey(User, null=True, blank=True)
    created_date = models.DateTimeField(default=timezone.now)
    published_date = models.DateTimeField(blank=True, null=True)
    slug = models.SlugField(max_length=100, null=True)
    active = models.BooleanField(default=True)

    def __str__(self):
        return self.subject

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def close(self):
        self.active = False
        self.save()


class Comment(models.Model):
    content = models.CharField(max_length=600)
    post = models.OneToOneField(Post, on_delete=models.CASCADE)
    author = models.ForeignKey(User, null=True, blank=True)
    published_date = models.DateTimeField(blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return "Comment to post: {0} added by {1} at {2}.".format(self.post.subject, self.author, self.published_date)


class Answer(models.Model):
    content = models.TextField()
    post = models.OneToOneField(Post, on_delete=models.CASCADE)
    author = models.ForeignKey(User, null=True, blank=True)
    published_date = models.DateTimeField(blank=True, null=True)

    def publish(self):
        self.published_date = timezone.now()
        self.save()

    def __str__(self):
        return "Answer to post: {0} added by {1} at {2}.".format(self.post.subject, self.author, self.published_date)

Solution

    • Answer can be associated to only one post, so one to one
    • comment can only be associated with one post, so one to one
    • comment can only be associated with one answer, so one to one

    Remember that the order of classes matters in Python. Place the comment class at the end, so that you can create one to one relationships between both Post and Answer. In the current position you can only do it with Post.

    class Post(models.Model):
       ##
    class Answer(models.Model):
       ##
    class Comment(models.Model):
       post = models.OneToOneField(Post, on_delete=models.CASCADE, null=True, blank=True)
       answer = models.OneToOneField(Answer, on_delete=models.CASCADE, null=True, blank=True)