Django How To annotate/Group by & Display it in Serializer

Question:

I have following Model

class ModelAnswer(BaseModel):
    questions = models.ForeignKey(
        to=Question,
        on_delete=models.CASCADE
    )
    answer = models.TextField()
    user = models.ForeignKey(User, on_delete=models.CASCADE)

Basically usecase is answer can be added multiple time i.e at once 3 answer can be added and all answers needed to be added for particular question

I just made another model to keep track of these things in next model for my easiness.

class AnswerLog(BaseModel):
    answer = models.ForeignKey(to=ModelAnswer, on_delete=models.CASCADE, null=True, blank=True)
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
    order = models.PositiveIntegerField(null=True, blank=True)

I am getting my response in this format

[
   {
      "answer":{
         "id":42,
         "user":1,
         "questions":"what did you do today",
         "subcategory":"Circumstance",
         "is_intentional":"False",
         "answer":"I played well",
         "created_at":"2022-09-05T21:00:57.604051"
      },
      "order":1,
      "category":"sports"
   },
   {
      "answer":{
         "id":43,
         "user":1,
         "questions":"what was your achievment?",
         "subcategory":"Result",
         "is_intentional":"False",
         "answer":"a broked my leg",
         "created_at":"2022-09-05T21:00:57.626193"
      },
      "order":1,
      "category":"sports"
   }
]

I just want my above response in a bit easier format in this way just combine by order and category because both will be ( category can still be same for another answer so order will only be different for next answer i.e 2)

[{
     "answer":[{
             "id":42,
             "user":1,
             "questions":"what did you do today",
             "subcategory":"Circumstance",
             "is_intentional":"False",
             "answer":"I played well",
             "created_at":"2022-09-05T21:00:57.604051"
          },{
             "id":43,
             "user":1,
             "questions":"what was your achievment?",
             "subcategory":"Result",
             "is_intentional":"False",
             "answer":"a broked my leg",
             "created_at":"2022-09-05T21:00:57.626193"
          }],
          "order":1,
          "category":"sports",
       }
    ]

My serializer is as follows

class AnswerLogSerializer(serializers.ModelSerializer):
    answer = ListAnswerSerializer()

    category = serializers.CharField(source='answer.questions.category.name')

    class Meta:
        model = AnswerLog
        fields = ['answer','order', 'category']

My view is as

class ListAnswerLogView(generics.ListAPIView):
    serializer_class = serializers.AnswerLogSerializer

    def get_queryset(self):
        return AnswerLog.objects.all()
Asked By: nava

||

Answers:

View

from collections import defaultdict

class ListAnswerLogView(ListAPIView):
    serializer_class = AnswerLogSerializer

    def get_queryset(self):
        grouped_answers = defaultdict(lambda: dict(answer=set()))

        for answer_log in AnswerLog.objects.all():
            grouped_by_key = (
                answer_log.order,
                answer_log.answer.questions.category
            )
            grouped_answers[grouped_by_key]['answer'].add(answer_log.answer)

        for key in grouped_answers:
            grouped_answers[key].update(dict(
                order=key[0],
                question_category=key[1]
            ))

        return grouped_answers.values()

Serializer

class AnswerLogSerializer(serializers.ModelSerializer):
    answer = ListAnswerSerializer(many=True)

    category = serializers.CharField(source='question_category.name')

    class Meta:
        model = AnswerLog
        fields = ['answer', 'order', 'category']

P.S. i tried a lot to solve the problem just using django queryset features, but each of them leads to a problem. So I went this way to use dictionary to solve the problem.

Answered By: Amrez