DRF系列總結三:批量更新介面的一種寫法
- 2019 年 10 月 4 日
- 筆記
項目中需要寫一個批量更新資源的介面:/matrix/batch_upate/,請求參數如下:
[ { "id": 71, "priority": "1" }, { "id": 69, "priority": "1" }, { "id": 70, "priority": "2" } ]一次介面提交,批量更新三條數據的priority欄位 ,在DRF框架中,要實現這樣的介面,需要在視圖類PriorityMatrixViewSet中添加一個自定義介面,比如batch_update方法,並定義序列化類MatrixListSerializer對介面參數進行校驗,最後再定義一個批量更新的方法batch_update,並在視圖類中校驗通過後進行批量更新操作,如圖所示:


測試一下介面,立刻報錯了:

序列化類中新增的方法batch_update不見了?明明我定義的類是MatrixListSerializer,這裡報錯為什麼是ListSerializer?
於是,看了下MatrixListSerializer的基類ModelSerializer的定義,並順著往上捋,找到了類創建和初始化的地方:__new__方法和__init__方法:

眾所周知,__new__方法創造了對象,__init__方法進一步修改了__new__方法創造的對象,從前者的注釋可以看出,作者對__new__方法做了個小動作:根據many=True的屬性,返回了默認的列表序列化類ListSerializer,這就解釋了前面的報錯。同時從many_init方法中可以看出,我們可以自定義列表序列化類:

默認的序列化類中寫了明確的注釋,它不知道如何批量更新(最多支援批量創建),但是你可以自己擴展,繼承這個類,並重寫update方法即可。

最終,我們可以通過Meta類的list_serializer_class屬性來啟用我們自定義的序列化類:

接下來,我們在update方法中實現了批量更新操作,但是,這種寫法需要多次資料庫交互,需要頻繁建立資料庫連接,有沒有更好的解法?

不想重複造輪子,逛了一下github,發現真的有人提供了一個工具:

啥原理?看下bulk_update方法,跳過前面的邏輯,看下最後神奇的sql語句吧:

把sql語句列印出來,豁然開朗,原來是結合update和case when的條件更新sql:

最後,我們藉助這個工具,就可以通過一次sql操作實現批量更新了:

最後,總結一下,DRF默認是不支援批量更新介面的,需要自己實現一個自定義介面,這個介面的實現方式有很多種,上面給大家列出了我的解決方法,希望能啟發到你。