如何使用 Django Rest Framework 为列表和详细信息视图设置不同的序列化程序?

Posted

技术标签:

【中文标题】如何使用 Django Rest Framework 为列表和详细信息视图设置不同的序列化程序?【英文标题】:How do I set different Serializer for list and detail view with Django Rest Framework? 【发布时间】:2014-09-08 16:34:27 【问题描述】:

如何在使用viewsets.ModelViewSetHyperlinkedSerializer 时为列表和详细信息视图设置不同的序列化程序?

我通过定义listretrive (here's an example) 了解如何使用viewsets.ViewSet 来实现它,但我不知道如何优雅地使其适应viewsets.ModelViewSet

【问题讨论】:

***.com/questions/22616973/… 【参考方案1】:

我改编了来自“Django rest framework, use different serializers in the same ModelViewSet”的答案,对我很有帮助,希望对你有用:

class MyModelViewSet(viewsets.MyModelViewSet):

    queryset = MyModel.objects.all()
    serializer_class = MyModelListSerializer
    detail_serializer_class = MyModelDetailSerializer

    def get_serializer_class(self):
        if self.action == 'retrieve':
            if hasattr(self, 'detail_serializer_class'):
                return self.detail_serializer_class

        return super(MyModelViewSet, self).get_serializer_class()

在这种情况下,您只需指定两个序列化程序并根据操作使用一个。但是,这可以更通用(适用于所有操作),如下所示:

class MyModelViewSet(viewsets.MyModelViewSet):

    queryset = MyModel.objects.all()
    serializer_class = MyModelSerializer

    action_serializers = 
        'retrieve': MyModelDetailSerializer,
        'list': MyModelListSerializer,
        'create': MyModelCreateSerializer
    

    def get_serializer_class(self):

        if hasattr(self, 'action_serializers'):
            return self.action_serializers.get(self.action, self.serializer_class)

        return super(MyModelViewSet, self).get_serializer_class()

【讨论】:

API 请求列表与详细信息有何不同? 它也非常适合我的用例。你能解释一下第二种方法吗?【参考方案2】:

Viewsets 扩展了 GenericAPIView 类,因此您可以使用this part of the documentation 来解决您的问题。基本上,您需要重写 get_serializer_class 并根据您的请求返回不同的序列化程序。

【讨论】:

【参考方案3】:

我为这项工作创建了这个小包。 drf_custom_viewsets。

它有CustomSerializerViewSet,继承自ModelViewSet,可以让你为不同的动作设置不同的序列化器。

【讨论】:

【参考方案4】:

从 2021 年开始,我将采取不同的做法,一种更好、更通用的方法是这样做:

class PlayersListViewSet(viewsets.ModelViewSet):
    queryset = Player.objects.all()
    serializer_class = PlayersListSerializer
    http_method_names = ['get', 'post']
    pagination_class = None
    filter_backends = [filters.OrderingFilter]
    ordering_fields = ['name']

    serializer_class_by_action = 
        'retrieve': PlayersDetailSerializer,
        'list': PlayersListSerializer,
    

    def get_serializer_class(self):

        if hasattr(self, 'serializer_class_by_action'):
            return self.serializer_class_by_action.get(self.action, self.serializer_class)

        return super(MyModelViewSet, self).get_serializer_class()

    def get_queryset(self):
        queryset = Player.objects.all()
        team_id = self.request.query_params.get('team', None)

        if team_id:
            try:
                queryset = queryset.filter(team=team_id)
            except ValueError:
                raise exceptions.ParseError()
        return queryset

这里action是序列化器使用的方法,listdef list的情况下,retrievedef retrieve的情况下等等..

【讨论】:

【参考方案5】:

感谢@bbengfort,我提供了一个简单的解决方案,无需创建新的ViewSet

Django ViewSet 中每个操作的不同序列化器

TL;DR

在下面的代码中,我们基于Django documentation 覆盖get_serializer_class,并且如果需要,我们会为每个操作指定不同的序列化程序:

Views.py

class TestAPIView(viewsets.ModelViewSet):
    permission_classes = (IsAuthenticated,)
    serializer_class = TestAPISerializer

    serializer_class_by_action = 
        'update_me': UpdateMeSerializer,
    

    def get_serializer_class(self):

        if hasattr(self, 'serializer_class_by_action'):
            return self.serializer_class_by_action.get(self.action, self.serializer_class)

        return self.serializer_class

    @action(detail=True, methods=['patch'], url_name='Update Me', url_path='updateme')
    def update_me(self, request, pk=None):
        # Write your own logic
        return Response("OK")

Serializers.py

class UpdateMeSerializer(serializers.Serializer):
    count = serializers.CharField(required=False, allow_null=True, default=10)
    class Meta:
        fields = ['count']

【讨论】:

以上是关于如何使用 Django Rest Framework 为列表和详细信息视图设置不同的序列化程序?的主要内容,如果未能解决你的问题,请参考以下文章

django.test.client 上的 Django rest 框架导入错误

无法使用 Django Rest 框架发送压缩的 gzip 数据

Django 和 Django 休息框架

Django前后端分离——drf

Django REST to React - 无需密码即可获取社交身份验证令牌

尽管有 AllowAny 权限,django-rest-framework 在 POST、PUT、DELETE 上返回 403 响应