首页 > 解决方案 > 序列化程序是否有 get_model 等效项?

问题描述

我已经阅读了有关序列化程序和谷歌搜索的文档(很多),但还没有找到我正在寻找的确切答案。

我正在尝试编写一个通用的“归档”过程(类)来处理根据 URL 中传递的内容将任何模型实例的状态字段更改为“归档”。

例如:

example.com/archive/clients.client/123

这会将 Client 模型的 ID 123 的状态更改为“已归档”。

这是我的 URLconf:

path('archive/<model>/<int:pk>/', Archive.as_view()),

这是我的视图类。我首先让它适用于特定模型,所以我复制了该代码并试图使其更通用。另外,我知道这需要更多的防弹,但我试图展示我的代码的最简单版本。

class Archive(RetrieveAPIView):

    def retrieve(self, request, model=None, pk=None, *args, **kwargs):
        app, model_name = model.split('.')

        get_model = apps.get_model
        model = get_model(app, model_name)
        self.queryset = model.objects.all()

        instance = self.get_object(pk=pk)

        if instance.status == 'archived':
            return APIMessage('That item has already been archived.', message_code='already_archived')

        setattr(instance, 'status', 'archived')
        instance.save()

        serializer = self.get_serializer(instance)
        return Response(serializer.data)

当我尝试按原样运行时,我得到:

'Archive' should either include a `serializer_class` attribute, or override the `get_serializer_class()` method.

这几乎是我所期望的,但我没有任何东西可以从一开始就将 serializer_class 设置为,如果我将其设置为 None,我会得到同样的错误。当然,我已经知道 get_serializer_class,但这就是我需要 get_model 之类的东西的地方,只是它会根据我从 URL 确定的模型返回序列化程序类。

标签: djangoserializationdjango-rest-framework

解决方案


由于您正在更新资源,因此您应该使用支持 PUT/PATCH 请求的视图,这些请求正是为了通过设计(在 HTTP 中)更新属性。

RetrieveAPIView是:

用于只读端点以表示单个模型实例

在您的特定情况下,您应该使用 DRF 中最通用APIView的,因为它不需要定义serializer_class和其他您不会使用的属性。

from rest_framework.views import APIView


class Archive(APIView):
    def put(self, request, model=None, pk=None, *args, **kwargs):
        app, model_name = model.split('.')

        get_model = apps.get_model
        model = get_model(app, model_name)
        self.queryset = model.objects.all()

        instance = self.get_object(pk=pk)

        if instance.status == 'archived':
            return APIMessage('That item has already been archived.', message_code='already_archived')

        setattr(instance, 'status', 'archived')
        instance.save()

        return Response({'success': True})

    def patch(self, request, *args, **kwargs):
        return self.put(request, *args, **kwargs)

这应该做的工作。我还映射了 PATCH 方法来执行 PUT 逻辑,这意味着您可以使用这两种 HTTP 方法来更新您的模型实例。

现在您的视图在 APIView 的帮助下尽可能通用。


推荐阅读