django rest framework的ModelViewSet非常爽,省了一大堆業務邏輯代碼,跟自己手寫restful的API 比至少減了100多行代碼,而且serializer這種東西都是複製就行,少耗費好多腦細泡。create和update的時候的各種異常根本不用自己檢查,直接就能報出來,加上django的國際化功能,直接甩中文,賊輕鬆,類似這樣:
{
"name": [
"具有 人物名稱 的 人物 已存在。"
],
"category": [
"列表不能爲空。"
]
}
配合rest framework的Response和status,根據http狀態碼判斷返回狀態然後直接讀取數據體,非常方便。不過和前端配合的話,需要返回code和msg,所以要自定義一下返回內容。根據serializer.errors的情況就可以判斷返回是否異常,這樣可以從return Response
的地方做個修改就可以把所有返回內容都加上code和msg了,不用每個return
都寫。
如果serializer.errors有值,就是報錯了,就返回
{'code': 0, 'msg': '失敗', 'data': serializer.errors}
如果沒報錯,就返回
{'code': 1, 'msg': '成功', 'data': serializer.data}
既然所有Response都要調整,最好當然直接改Response,一看源碼,還防着我這手兒,不讓傳serializer,只讓傳serializer.data:
if isinstance(data, Serializer):
msg = (
'You passed a Serializer instance as data, but '
'probably meant to pass serialized `.data` or '
'`.error`. representation.'
)
raise AssertionError(msg)
雖然仍然可以改,不過這個Response的位置太根部了,除非改源碼,否則改了Response,所有return Response
的地方都要改。那就換個思路,改ModelViewSet吧。
ModelViewSet直接繼承了6個父類:
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
"""
pass
只要調整那幾個混入類裏面的對應的方法的return Response
就可以了。以update爲例:
class MyModelViewSet(viewsets.ModelViewSet):
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
is_valid = serializer.is_valid(raise_exception=False)
#######
if not is_valid:
return Response({'code': 0, 'msg': '失敗', 'data': serializer.errors})
self.perform_update(serializer)
######
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
return Response({'code': 1, 'msg': '成功', 'data': serializer.data})
注意is_valid = serializer.is_valid(raise_exception=False)
源碼是raise_exception=True
,要改成False,不然就拋出異常在serializer裏處理,不走下面的代碼了。
然後只要在繼承ModelViewSet
的地方改爲繼承MyModelViewSet
就ok了。