【问题标题】:DRF options request on viewset with multiple serializers具有多个序列化程序的视图集上的 DRF 选项请求
【发布时间】:2020-05-21 06:51:44
【问题描述】:

我在我的视图集上使用了一个 mixin,以便可以在不同的 viewset actions 和任何 custom actions 上使用多个序列化程序。

我有一个名为invoice 的额外操作,它只是一个普通更新,但使用了不同的序列化程序。我需要在端点执行 OPTIONS 请求以获取 <select> 元素的选项。问题是当我执行请求时,它会从默认更新中获取序列化程序 - OrderSerializer 而不是 InvoiceSerializer。如何从正确的序列化程序中获取选项?

class MultipleSerializerMixin:
    """
    Mixin that allows for multiple serializers based on the view's
    `serializer_action_classes` attribute.

    ex.
        serializer_action_classes = {
            'list': ReadOnlyListSerializer,
            'retrieve': ReadOnlyDetailSerializer,
        }
    """
    def get_serializer_class(self):
        try:
            return self.serializer_action_classes[self.action]
        except (KeyError, AttributeError):
            return super().get_serializer_class()


class OrderAPIViewSet(MultipleSerializerMixin,
                      viewsets.ModelViewSet):
    queryset = Order.objects.all()
    serializer_class = serializers.OrderSerializer
    serializer_action_classes = {
        'invoice': serializers.InvoiceSerializer,
    }

    @action(detail=True, methods=['put'], url_name='invoice')
    def invoice(self, request, *args, **kwargs):
        """
        Invoice the order and order lines.
        """
        return self.update(request, *args, **kwargs)

更新:

因此,在检查了determine_actions method in metadata.SimpleMetadata 之后,似乎在执行 OPTIONS 请求时,view.actionmetadata 而不是invoice,这就解释了为什么序列化程序默认为view.serializer_class

【问题讨论】:

    标签: django django-rest-framework


    【解决方案1】:

    一种解决方法是创建一个extra action as a schema endpoint,可以通过手动将操作设置为invoice 的GET 请求进行访问。

    @action(detail=True, methods=['get', 'put'])
    def invoice_schema(self, request, *args, **kwargs):
        self.action = 'invoice'
        data = self.metadata_class().determine_metadata(request, self)
        return Response(data, status=status.HTTP_200_OK)
    

    如果您有多个使用不同序列化程序的操作,一个更干燥的解决方案是覆盖视图的 options 方法并从查询参数设置操作。这可以添加到 MultipleSerializerMixin 以使其成为使用此 mixin 的所有视图的默认行为。

    def options(self, request, *args, **kwargs):
        self.action = request.query_params.get('action')
        return super().options(request, *args, **kwargs)
    

    【讨论】:

      【解决方案2】:

      覆盖get_serializer_class 方法就足够了,OPTIONS 请求将检测使用哪个序列化器:

      def get_serializer_class(self):
         if self.request.method == 'GET':
            return ReadOnlyShopSerializer
         return ShopSerializer
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-12-17
        • 2019-03-16
        • 1970-01-01
        • 2016-11-05
        • 2017-10-30
        • 1970-01-01
        • 1970-01-01
        • 2017-03-22
        相关资源
        最近更新 更多