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

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