• Django-Rest-Framework的视图和路由


    Django-Rest-Framework的视图和路由

    Django-Rest-Framework的视图

    APIView

    django中写CBV的时候继承的是View,rest_framework继承的是APIView,那么他们两个有什么不同呢

    urlpatterns = [
        url(r'^book$', BookView.as_view()),
        url(r'^book/(?P<id>d+)$', BookEditView.as_view()),
    ]
    

    可以看到,不管是View还是APIView最开始调用的都是as_view()方法,那走进源码看看

    我们能看到,APIView继承了View, 并且执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。
    
    那我们看看View中的as_view()方法做了什么
    
    我们看到了~在View中的as_view方法返回了view函数,而view函数执行了self.dispatch()方法~~但是这里的dispatch方法应该是我们APIView中的
    
    我们去initialize_request中看下把什么赋值给了request,并且赋值给了self.request, 也就是我们在视图中用的request.xxx到底是什么
    
    我们看到,这个方法返回的是Request这个类的实例对象
    我们注意我们看下这个Request类中的第一个参数request,是我们走我们django的时候的原来的request~
    
    我们看到了,这个Request类把原来的request赋值给了self._request, 也就是说以后_request是我们老的request,新的request是我们这个Request类
    
    那我们继承APIView之后请求来的数据都在哪呢~~
    
    我们用了rest_framework框架以后,我们的request是重新封装的Request类~
    
    request.query_params 存放的是我们get请求的参数
    
    request.data 存放的是我们所有的数据,包括post请求的以及put,patch请求
    
    相比原来的django的request,我们现在的request更加精简,清晰了~~~
    
    现在我们知道了APIView和View的一些区别~~当然还有~~后面还会说~~
    
    我们写的视图可能对多个表进行增删改查,就导致我们的视图特别多重复的代码~~
    
    那么我们尝试着来进行封装一下~~
    

    第一次封装

    APIView视图

    class BookView(APIView):
    
        def get(self, request):
            query_set = Book.objects.all()
            book_ser = BookSerializer(query_set, many=True)
            return Response(book_ser.data)
    
        def post(self, request):
            query_set = request.data
            book_ser = BookSerializer(data=query_set)
            if book_ser.is_valid():
                book_ser.save()
                return Response(book_ser.validated_data)
            else:
                return Response(book_ser.errors)
    
    
    class BookEditView(APIView):
    
        def get(self, request, id):
            query_set = Book.objects.filter(id=id).first()
            book_ser = BookSerializer(query_set)
            return Response(book_ser.data)
    
        def patch(self, request, id):
            query_set = Book.objects.filter(id=id).first()
            book_ser = BookSerializer(query_set, data=request.data, partial=True)
            if book_ser.is_valid():
                book_ser.save()
                return Response(book_ser.validated_data)
            else:
                return Response(book_ser.errors)
    
        def delete(self, request, id):
            query_set = Book.objects.filter(id=id).first()
            if query_set:
                query_set.delete()
                return Response("")
            else:
                return Response("删除的书籍不存在")
    

    第一次封装

    class GenericAPIView(APIView):
        queryset = None
        serializer_class = None
    
        def get_queryset(self):
            return self.queryset.all()
    
        def get_serializer(self, *args, **kwargs):
            return self.serializer_class(*args, **kwargs)
    
    
    class ListModelMixin(object):
        def list(self, request, *args, **kwargs):
            queryset = self.get_queryset()
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)
    
    
    class CreateModelMixin(object):
        def create(self, request, *args, **kwargs):
            serializer = self.get_serializer(data=request.data)
            if serializer.is_valid():
                serializer.save()
                return Response(serializer.validated_data)
            else:
                return Response(serializer.errors)
    
    
    class RetrieveModelMixin(object):
        def retrieve(self, request, id, *args, **kwargs):
            book_obj = self.get_queryset().filter(pk=id).first()
            book_ser = self.get_serializer(book_obj)
            return Response(book_ser.data)
    
    
    class UpdateModelMixin(object):
        def update(self, request, id, *args, **kwargs):
            book_obj = self.get_queryset().filter(pk=id).first()
            book_ser = self.get_serializer(book_obj, data=request.data, partial=True)
            if book_ser.is_valid():
                book_ser.save()
                return Response(book_ser.validated_data)
            else:
                return Response(book_ser.errors)
    
    
    class DestroyModelMixin(object):
        def destroy(self, request, id, *args, **kwargs):
            queryset = self.get_queryset()
            try:
                queryset.get(pk=id).delete()
                return Response("")
            except Exception as e:
                return Response("信息有误")
    # 我们把公共的部分抽出来 这样不管写多少表的增删改查都变的很简单
    # 这样封装后我们的视图会变成这样
    
    class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)
    
    
    class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
        def get(self, request, id, *args, **kwargs):
            return self.retrieve(request, id, *args, **kwargs)
    
        def patch(self, request, id, *args, **kwargs):
            return self.update(request, id, *args, **kwargs)
    
        def destroy(self, request, id, *args, **kwargs):
            return self.delete(request, id, *args, **kwargs)
    

    我们封装的GenericAPIView,包括封装每个方法的类,其实框架都帮我们封装好了~~

    我们可以直接继承这些类来实现上面的视图可是还有没有更简单的方法呢~我们再次封装一下~~

    第二次封装

    # 上面我们写的继承类太长了~~我们再改改
    
    class ListCreateAPIView(GenericAPIView, ListModelMixin, CreateModelMixin):
        pass
    
    
    class RetrieveUpdateDestroyAPIView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
        pass
    
    
    class BookView(ListCreateAPIView):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)
    
    
    class BookEditView(RetrieveUpdateDestroyAPIView):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
        def get(self, request, id, *args, **kwargs):
            return self.retrieve(request, id, *args, **kwargs)
    
        def patch(self, request, id, *args, **kwargs):
            return self.update(request, id, *args, **kwargs)
    
        def delete(self, request, id, *args, **kwargs):
            return self.delete(request, id, *args, **kwargs)
    

    这次我们只是让继承变的简单了一点而已,好像并没有什么大的进步
    我们可不可以把这两个视图合并成一个视图呢~~~框架给我们提供了一个路由传参的方法

    我们看下ViewSetMixin

    action这个默认参数其实就是我们路由可以进行传参了
    
    下面这个循环~可以看出~我们要传的参数是一个字段~key应该是我们的请求方式,value应该对应我们处理的方法~
    
    这样我们每个视图就不用在写函数了~因为已经和内部实现的函数相对应了~
    

    第三次封装

    路由 urls.py

    urlpatterns = [
        # url(r'^book$', BookView.as_view()),
        # url(r'^book/(?P<id>d+)$', BookEditView.as_view()),
        url(r'^book$', BookView.as_view({"get": "list", "post": "create"})),
        url(r'^book/(?P<pk>d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),
    ]
    

    第三次封装

    from rest_framework.viewsets import ViewSetMixin
    
    # class BookView(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
    #     queryset = Book.objects.all()
    #     serializer_class = BookSerializer
    
    
    # 如果我们再定义一个类
    class ModelViewSet(ViewSetMixin, ListCreateAPIView, RetrieveUpdateDestroyAPIView):
        pass
    
    
    class BookView(ModelViewSet):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    

    我们现在的视图就只要写两行就可以了

    其实我们写的所有的视图~框架都帮我们封装好了

    注意一点~用框架封装的视图~我们url上的那个关键字参数要用pk~系统默认的

    奉献一张图来看下我们的继承顺序

    Django-Rest-Framework的路由

    我们上面的路由传参写的特别多~~框架也帮我们封装好了~

    from .views import BookView
    from rest_framework.routers import DefaultRouter
    
    router = DefaultRouter()
    router.register(r"book", BookView)
    
    urlpatterns = [
        # url(r'^book$', BookView.as_view()),
        # url(r'^book/(?P<id>d+)$', BookEditView.as_view()),
        # url(r'^book$', BookView.as_view({"get": "list", "post": "create"})),
        # url(r'^book/(?P<pk>d+)$', BookView.as_view({"get": "retrieve", "patch": "update", "delete": "destroy"})),
    
    ]
    urlpatterns += router.urls
    

    我们可以看到通过框架我们可以把路由视图都变的非常简单~~

    但是需要自定制的时候还是需要我们自己用APIView写,当不需要那么多路由的时候,也不要用这种路由注册~~

    总之一切按照业务需要去用~~~

  • 相关阅读:
    mock 数据模拟
    利用css绘制三角形,半圆等形状
    页面底部固定
    Form Data格式传参
    element 页面显示效果及需要注意的点
    vue 组件加载顺序
    vue-router 导航钩子
    vue 总结
    前端开发的碎碎念
    值匹配的方式
  • 原文地址:https://www.cnblogs.com/xiao-xue-di/p/9879333.html
Copyright © 2020-2023  润新知