【问题标题】:How can I PUT/POST JSON data to a ListSerializer?如何将 JSON 数据 PUT/POST 到 ListSerializer?
【发布时间】:2015-03-08 07:43:17
【问题描述】:

我正在阅读有关自定义多个更新 here 的信息,但我还没有弄清楚在什么情况下会调用自定义 ListSerializer 更新方法。我想一次更新多个对象,我现在不担心多次创建或删除。

来自文档中的示例:

# serializers.py
class BookListSerializer(serializers.ListSerializer):
    def update(self, instance, validated_data):
        # custom update logic
        ...

class BookSerializer(serializers.Serializer):
    ...
    class Meta:
        list_serializer_class = BookListSerializer

还有我的视图集

# api.py
class BookViewSet(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

我的网址设置使用DefaultRouter

# urls.py
router = routers.DefaultRouter()
router.register(r'Book', BookViewSet)

urlpatterns = patterns('',                       
    url(r'^api/', include(router.urls)),
    ...

所以我使用DefaultRouter 进行了设置,这样/api/Book/ 将使用BookSerializer

一般的想法是,如果我 POST/PUT/PATCH 一个 JSON 对象数组到/api/Book/,那么序列化程序应该切换到BookListSerializer

我已尝试将 POST/PUT/PATCH JSON 数据列表添加到此 /api/Book/,如下所示:

[ {id:1,title:thing1}, {id:2, title:thing2} ]

但它似乎仍然使用BookSerializer 而不是BookListSerializer 来处理数据。如果我通过 POST 提交,我会得到 Invalid data. Expected a dictionary, but got list。如果我通过 PATCH 或 PUT 提交,则会收到 Method 'PATCH' not allowed 错误。

问题: 我是否必须调整DefaultRouterBookViewSetallowed_methods 以允许列表的POST/PATCH/PUT?通用视图是否未设置为与 ListSerializer 一起使用?

我知道我可以为此编写自己的列表反序列化程序,但我正在努力了解 DRF 3 中的新功能,看起来这应该可以工作,但我只是缺少一些约定或一些选项.

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    默认情况下,Django REST 框架假定您不处理批量数据的创建、更新或删除。这是因为 99% 的人没有处理批量数据创建,并且DRF leaves the other 1% to third-party libraries

    在 Django REST framework 2.x 和 3.x 中,第三方包exists for this.

    现在,您正在尝试进行批量创建,但您收到一个错误提示

    无效数据。需要一本字典,但得到了列表

    这是因为您发送的是要创建的对象列表,而不是只发送一个。您可以通过几种方法解决此问题,但最简单的方法是在序列化程序是列表时将override get_serializer on your viewadd the many=True flag 发送到序列化程序。

    def get_serializer(self, *args, **kwargs):
        if "data" in kwargs:
            data = kwargs["data"]
    
            if isinstance(data, list):
                kwargs["many"] = True
    
        return super(MyViewSet, self).get_serializer(*args, **kwargs)
    

    这将允许 Django REST 框架知道在批量创建对象时自动使用ListSerializer。现在,对于更新和删除等其他操作,您将需要覆盖默认路由。我将假设您使用的是routes provided by Django REST framework bulk,但您可以随意使用任何您想要的方法名称。

    您还需要将批量PUTPATCH 的方法添加到视图中。

    from rest_framework.response import Response
    
    def bulk_update(self, request, *args, **kwargs):
        partial = kwargs.pop("partial", False)
    
        queryset = self.filter_queryset(self.get_queryset))
    
        serializer = self.get_serializer(instance=queryset, data=request.data, many=True)
        serializer.is_valid(raise_exception=True)
    
        self.perform_update(serializer)
    
        return Response(serializer.data)
    
    def partial_bulk_update(self, *args, **kwargs):
        kargs["partial"] = True
        return super(MyView, self).bulk_update(*args, **kwargs)
    

    这不会开箱即用,因为默认情况下 Django REST 框架不支持批量更新。这意味着你也have to implement your own bulk updates。当前代码将处理批量更新,就像您尝试更新整个列表一样,这就是旧的批量更新包以前的工作方式。

    虽然您没有要求批量删除,但这并不是特别困难。

    def bulk_delete(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        self.perform_delete(queryset)
        return Response(status=204)
    

    这与删除所有对象的效果相同,与旧的批量插件相同。

    此代码均未经过测试。如果不起作用,请考虑将其作为详细示例。

    【讨论】:

    • 谢谢。解决了这个问题。现在我正在向/api/Book/ 提交一个列表。如果我通过 POST 提交,我会得到 Invalid data. Expected a dictionary, but got list.,如果我通过 PATCH 或 PUT 提交,我会得到 Method 'PATCH' not allowed.。如果有帮助,我正在使用DefaultRouterModelViewSet
    • 我已更新答案以详细解决您的问题。希望它涵盖了您问题的多个部分。运气好的话,第三方包将在不久的将来更新以支持 3.0。
    • 太棒了,谢谢。我想我的问题可以归结为“看起来 DRF 现在在 3.0 中有一些默认的批量更新行为?”答案是“不完全”。您的代码示例正是我所需要的,我会对其进行测试并在必要时进行更新。
    • 非常感谢这个凯文 - 这在这里为我们解决了问题:github.com/burke-software/django-sis/commit/…
    • 更新了 DRF-bulk 现在支持 DRF2 和 DRF3 的答案! - github.com/miki725/django-rest-framework-bulk
    猜你喜欢
    • 2012-09-30
    • 1970-01-01
    • 2018-06-30
    • 1970-01-01
    • 1970-01-01
    • 2015-11-08
    • 2016-12-24
    • 1970-01-01
    • 2015-02-05
    相关资源
    最近更新 更多