Search code examples
pythondjangodjango-rest-frameworkdjango-serializer

Show most voted member of related model in serializer


I have the following models:

  • Question
class Question(models.Model):
    question_text = models.CharField(max_length=450)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    posted_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
  • Answer
class Answer(models.Model):
    question = models.ForeignKey(Question, related_name='answers', on_delete=models.CASCADE)
    answer_text = models.CharField(max_length=5000)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    posted_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

  • VoteAnswer
class VoteAnswer(models.Model):
    answer = models.ForeignKey(Answer, related_name='votes', on_delete=models.CASCADE)
    voted_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

Question Serializer

class QuestionSeriaizer(serializers.HyperlinkedModelSerializer):

    answer_count = serializers.SerializerMethodField()
    posted_by = UserDetailSerializer(read_only=True)

    class Meta:
        model = Question
        fields = ('url', 'id', 'question_text', 'created_at', 'updated_at', 'posted_by', 'answer_count', 'page',
                  'who_can_answer')
        depth = 1

    @staticmethod
    def get_answer_count(obj):
        return obj.answers.all().count()

What I want to achieve:

There should be a 'top_answer' field in the question serializer which has the answer with the most votes.

I have tried the following with no success:

class QuestionSeriaizer(serializers.HyperlinkedModelSerializer):

    answer_count = serializers.SerializerMethodField()
    top_answer = serializers.SerializerMethodField()
    posted_by = UserDetailSerializer(read_only=True)

    class Meta:
        model = Question
        fields = ('url', 'id', 'question_text', 'created_at', 'updated_at', 'posted_by', 'answer_count', 'page',
                  'who_can_answer', 'top_answer')
        depth = 1

    @staticmethod
    def get_answer_count(obj):
        return obj.answers.all().count()

    @staticmethod
    def get_top_answer(obj):
        return obj.answers.annotate(total_votes=obj.answers.votes.all().count()).order_by('total_votes').first()


Solution

  • You can try like this using Count:

    from django.db.models import Count
    
    class QuestionSeriaizer(serializers.HyperlinkedModelSerializer):
        # rest of the code
        def get_top_answer(obj):
            return obj.answers.annotate(total_votes=Count('votes')).order_by('total_votes').first().answer_text
    

    If you have AnswerSerializer, then you can try:

    def get_top_answer(obj):
       answer = obj.answers.annotate(total_votes=Count('votes')).order_by('total_votes').last()
       return AnswerSerializer(answer).data