2015-01-09 73 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