Django Как аннотировать/группировать по и отображать в сериализаторе

У меня есть следующая модель

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

В основном используется случай, когда ответ может быть добавлен несколько раз, т.е. сразу 3 ответа могут быть добавлены и все ответы должны быть добавлены для конкретного вопроса

Я просто сделал еще одну модель, чтобы отслеживать эти вещи в следующей модели для моего удобства.

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)

Я получаю ответ в таком формате

[
   {
      "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"
   }
]

Я просто хочу, чтобы мой вышеупомянутый ответ был немного проще в формате, таким образом, просто объедините по порядку и категории, потому что оба будут (категория может быть такой же для другого ответа, поэтому порядок будет отличаться только для следующего ответа, т.е. 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",
       }
    ]

Мой сериализатор выглядит следующим образом

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

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

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

Мое мнение таково

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

    def get_queryset(self):
        return AnswerLog.objects.all()

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. Я много раз пытался решить проблему просто используя возможности django queryset, но каждый из них приводит к проблеме. Поэтому я пошел этим путем, используя словарь для решения проблемы.
Вернуться на верх