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方法中實現了批量更新操作,但是,這種寫法需要多次資料庫交互,需要頻繁建立資料庫連接,有沒有更好的解法?

一條sql

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

bulk_update

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

bulk_update

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

條件更新sql

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

最後的update

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

Tags: