2015-01-09 72 views
20

我在阅读有关定制多个更新here,我还没有想出在什么情况下调用自定义ListSerializer更新方法。我想一次更新多个对象,我并不担心目前多次创建或删除。如何发布/放JSON数据到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中的新功能的最新,它看起来像这应该工作,但我只是缺少一些约定或一些选项。

回答

33

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

在Django REST框架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) 

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

这段代码没有经过测试。如果它不起作用,请将其视为一个详细示例。

+0

谢谢。修正了。现在我将一个列表提交给'/ api/Book /'。如果我通过POST提交,我会得到'无效的数据。期望一个字典,但有list.',如果我通过PATCH或PUT提交,那么我得到一个'Method'PATCH'不允许。“。如果有帮助,我使用'DefaultRouter'和'ModelViewSet'。 – petroleyum 2015-01-10 21:33:48

+0

我已经更新了答案,详细解答了您的问题**。希望它涵盖了你的问题的多个部分。幸运的是,第三方软件包将在不久的将来更新到支持3.0。 – 2015-01-11 01:19:34

+0

太棒了,谢谢。我想我的问题可能被归结为“现在3.0看起来DRF现在有一些默认的批量更新行为?”答案是“不完全”。您的代码示例正是我所需要的,我会对其进行测试并在必要时进行更新。 – petroleyum 2015-01-11 14:24:16