没有原始 sql 查询的 DRF 嵌套序列化

DRF nested serialization without raw sql query

我已经被这个问题困扰几天了。尝试了不同的方法但没有成功。我有两个 classes - Poll 和 PollAnswer。他们在这里:

class Poll(Model):
    title = CharField(max_length=256)
class PollAnswer(Model):
    user_id = CharField(max_length=10)
    poll = ForeignKey(Poll, on_delete=CASCADE)
    text = CharField(max_length=256)

获取答案 used_id 等于带有该用户答案嵌套列表的特定字符串的民意调查列表的正确方法是什么?像这样:

{
    'poll_id': 1,
    'answers' : {
        'user1_answer1: 'answer_text1',
        'user1_answer2: 'answer_text2',
        'user1_answer3: 'answer_text3',    
    },
}

如果这是一个简单的问题,我可能需要一些关于 django orm 的好指南。

我尝试的第一件事是制作序列化器的方法(继承自 drf 的 ModelSerializer),但得到一个错误,这个 class 不能有这样的方法。之后我尝试将序列化程序的字段与 ForeignKey 一起使用,但得到的是嵌套在答案中的民意调查。现在我相信我可以做到 Polls.objects.raw('some_sql_query') 但这可能不是最好的方法。

文档中描述了您的问题(也是最佳实践)。 您可以使用嵌套序列化器:

https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers

否则,如果您想按照您的描述保留嵌套答案: 我会使用序列化方法字段

https://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

然后对你的答案做一个小循环......和return你想要的任何格式。

好的,感谢您的帮助最终代码是:

序列化器:

class UserPollsSerializer(ModelSerializer):

    answers = SerializerMethodField()

    # drf automatically finds this method by mask get_{field}
    def get_answers(self, obj):
        answers = self.context.get('answers_qs').filter(poll=obj)
        data = QuestionAnswerSerializer(answers, many=True).data
        return data

    class Meta:
        model = Poll
        fields = '__all__'

查看:

class PollMVS(ModelViewSet):
    serializer_class = PollSerializer
    permission_classes = [IsAdminUser]
    queryset = Poll.objects.all()

    # getting polls with answers by user_id
    @action(detail=False, methods=['get'])
    def user_polls(self, request):
        
        # here i get all polls with user's answers
        user_id = request.GET.get('user_id')
        polls_ids = QuestionAnswer.objects.values('poll').filter(user_id=user_id).distinct()
        u_polls = Poll.objects.filter(pk__in=polls_ids)
        
        # and here i pass them as a queryset and answers' queryset as context in a separate serializer
        serializer = UserPollsSerializer(u_polls, many=True, context={'answers_qs': QuestionAnswer.objects.filter(user_id=user_id)})
        return Response(serializer.data)