django rest framework 自定義ModelViewSet的返回內容

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了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章