1

I am trying to get all data related to model Post using one single API call. This call should include post contents, comments, upvote and downvotes.

I have 4 models and Post model is a foreign key to every other model.

class Post(models.Model):
    title = models.CharField(max_length=200, null=True, blank=True)
    body = models.CharField(max_length=500, null=True, blank=True)

    def __str__(self):
        return str(self.title)


class UpVote(models.Model):
    post = models.OneToOneField(Post, related_name="upvote_post", on_delete=models.CASCADE)
    upvotes = models.IntegerField(default=0)


class DownVote(models.Model):
    post = models.OneToOneField(Post, related_name="downvote_post", on_delete=models.CASCADE)
    downvotes = models.IntegerField(default=0)


class Comment(models.Model):
    post = models.ForeignKey(Post, related_name="comment_post", on_delete=models.CASCADE)
    comment = models.CharField(max_length=200, null=True, blank=True)

I saw this solution in a post to combine data with a foreign key relationship that exists.

class UpVoteSerializer(serializers.ModelSerializer):
    class Meta:
        model = UpVote
        fields = "__all__"


class DownVoteSerializer(serializers.ModelSerializer):
    class Meta:
        model = DownVote
        fields = "__all__"


class CommentSerializer(serializers.ModelSerializer):
    class Meta:
        model = Comment
        fields = "__all__"


class PostSerializer(serializers.ModelSerializer):
    upvote = UpVoteSerializer(read_only=True, many=False)
    downvote = DownVoteSerializer(read_only=True, many=False)
    comments = CommentSerializer(read_only=True, many=True)

    class Meta:
        model = Post
        fields = ("id", "title", "body", "upvote", "downvote", "comments")

This is from the views.py file

@api_view(['GET'])
def postList(request):
    post = Post.objects.all().order_by('-id')
    serializer = PostSerializer(post, many=True)
    return Response(serializer.data)

This is the output that get returned

[
    {
        "id": 7,
        "title": "1st post",
        "body": "Body of 1st post"
    },
    {
        "id": 6,
        "title": "2nd post",
        "body": "Body of 2nd post"
    },
    {
        "id": 5,
        "title": "3rd post",
        "body": "Body of 3rd post"
    },
    {
        "id": 4,
        "title": "4th post",
        "body": "Body of 4th post"
    }
]

I don't know why it's not returning back the comments and the upvotes and downvotes.

3
  • upvote_post is accessor from Post model Commented Feb 1, 2021 at 5:31
  • @iklinac so I should just write "upvote_post" in the fields of PostSerializer? Commented Feb 1, 2021 at 5:38
  • @iklinac thank you. it kinda worked. I'm gonna work on it a little more. Can you answer the question. So I can accept it? Commented Feb 1, 2021 at 5:39

3 Answers 3

1

You do need to use related_name to go through reverse of the relation. You might use it as source field if you want to keep serializer field name

So for example

upvote = UpVoteSerializer(read_only=True, source='upvote_post')

Also it does not make much sense to have OneToOne relationship to keep vote count as you could just have upvotes directly in Post model

Sign up to request clarification or add additional context in comments.

Comments

1

Here you have defined Upvote, DownVote and Comment in another models and you have given related name to each foreign keys or OneToOne fields so, use that related name with serializers with source and you can access data of the related object.

upvote = UpVoteSerializer(read_only=True, source='upvote_post')
downvote = DownVoteSerializer(read_only=True, source='downvote_post')
comments = CommentSerializer(read_only=True, source='comment_post')

And here it is not a best practice to make another model to just keep a count of the upvote and downvote. you can easily have them in post models.

Comments

1
class allModelSerializer(serializers.Serializers):
    filed1_from_model1 = serializers.CharField(max_length=10)
    .....
    .....
    # number of fields u wants from different models

In views file just call

class viewsOne():
  def get():
    model1_data = model1_call
    model2_data = model2_call
    ....
    ....
  all_model = [model1_data,model2_data,......]

  # pass a response 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.