DRF ViewSet 额外操作(`@action`)serializer_class

问题描述 投票:0回答:3

当我尝试在视图集上使用 Django Rest Framework 额外操作时,我无法使装饰器的

serializer_class
工作。

class ClientViewSet(ModelViewSet):
    queryset = Client.objects.all()
    serializer_class = ClientSerializer

    def get_queryset(self):
        # Do things

    def get_serializer_class(self):
        if self.action in ["create"]:
            return CreateClientSerializer
        elif self.action in ["retrieve"]:
            return ClientDetailSerializer
        return self.serializer_class

    @action(detail=True, methods=["get"], serializer_class=ClientDetailSerializer)
    def get_by_name(self, request, name=None):
        """
        Get one Client searching by name.
        @param request:
        @param name: Client code
        @return: Response
        """
        queryset = get_object_or_404(Client, name__iexact=name)
        serializer = self.get_serializer(queryset)
        return Response(serializer.data)

因此,即使额外的操作据称会覆盖 ViewSet 默认序列化器类,我仍然得到

ClientSerializer
而不是
ClientDetailSerializer

官方文档指出...

装饰器允许您覆盖任何视图集级别的配置,例如

permission_classes
serializer_class
filter_backends
...:

我的

get_serializer_class
覆盖默认为 ViewSet
serializer_class
属性,用于我的额外操作。如果我理解正确的话,这基本上就是
GenericAPIView
get_serializer_class
在幕后所做的事情:

def get_serializer_class(self):
    """
    (...)
    """
    assert self.serializer_class is not None, (
        "'%s' should either include a `serializer_class` attribute, "
        "or override the `get_serializer_class()` method."
        % self.__class__.__name__
    )

    return self.serializer_class

我想我在这里遗漏了一些明显的东西。只是不明白什么...

如有任何帮助,我们将不胜感激。预先感谢:)

python-3.x django django-rest-framework django-serializer
3个回答
3
投票

当您重写

get_serializer_class
而不调用此类的超级时,超级类不会运行。 用户此:

    def get_serializer_class(self):
        if self.action in ["create"]:
            return CreateClientSerializer

        elif self.action in ["retrieve"]:
            return ClientDetailSerializer

        return super().get_serializer_class()

2
投票

为什么不这样使用呢?我猜你在 get_serializer_class 中做错了什么。

@action(detail=True, methods=["get"], serializer_class=ClientDetailSerializer)
def get_by_name(self, request, name=None):
    """
    Get one Client searching by name.
    @param request:
    @param name: Client code
    @return: Response
    """
    object = get_object_or_404(Client, name__iexact=name)
    serializer = ClientDetailSerializer(object)
    return Response(serializer.data)

0
投票
如果声明,

get_serializer_class
则优先,因此操作中的
serializer_class=ClientDetailSerializer
没有意义。

基本上

@action
装饰器创建一个新动作,就像 -
list
retrieve
etc

所以在这里你可以在

get_serializer_class
本身添加额外的条件返回,例如:

def get_serializer_class(self):
    if self.action in ["create"]:
        return CreateClientSerializer
    if self.action in ["retrieve"]:
        return ClientDetailSerializer
    # here self.action will be the name of the function name
    if self.action == "get_by_name":
        return ClientDetailSerializer
    return self.serializer_class

我知道在这里发帖已经太晚了,但可能会对像我这样的人有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.