Django 如何注释/分组并在序列化器中显示它

lor*_*ock 5 python django django-models django-rest-framework

我有以下型号

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

基本上用例是可以多次添加答案,即一次可以添加 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)
Run Code Online (Sandbox Code Playgroud)

我收到这种格式的回复

[
   {
      "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"
   }
]
Run Code Online (Sandbox Code Playgroud)

我只是希望我的上述回复以更简单的格式,这样只需按顺序和类别组合即可,因为两者都是(类别对于另一个答案仍然可以相同,因此下一个答案的顺序只会不同,即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",
       }
    ]
Run Code Online (Sandbox Code Playgroud)

我的序列化器如下

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

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

    class Meta:
        model = AnswerLog
        fields = ['answer','order', 'category']
Run Code Online (Sandbox Code Playgroud)

我的看法是

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

    def get_queryset(self):
        return AnswerLog.objects.all()
Run Code Online (Sandbox Code Playgroud)

小智 4

看法

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()
Run Code Online (Sandbox Code Playgroud)

串行器

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

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

    class Meta:
        model = AnswerLog
        fields = ['answer', 'order', 'category']
Run Code Online (Sandbox Code Playgroud)
PS 我尝试了很多方法来仅使用 django 查询集功能来解决问题,但是每个功能都会导致一个问题。于是我就这样用字典来解决问题。