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

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

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

【问题讨论】:

标签: django django-rest-framework


【解决方案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']
        
        

        【讨论】:

          猜你喜欢
          • 2020-05-27
          • 2018-10-09
          • 1970-01-01
          • 2016-04-14
          • 1970-01-01
          • 1970-01-01
          • 2016-09-29
          • 1970-01-01
          相关资源
          最近更新 更多