• DRF的视图和路由


    DRF的视图

    APIView

    Django中写CBV的时候继承的是View,rest_framework继承的是APIView,

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

    View和APIView调用的都as_view()方法,我们知道APIView继承了View,并且重写了as_view()方法,并执行了View中的as_view()方法,最后把view返回了,用csrf_exempt()方法包裹后去掉了csrf的认证。看下图:

    APIView还执行了dispatch方法,新的request是Request类的实例化对象,看下图:

    我们看看initialize_request中的代码实现了什么功能:

    点击Request可以看到Request类把原来的request赋值给了self._request,也就是说以后_request是我们旧的request,看下图:

    继承APIVIew之后的请求来的数据,看下图:

    当用了rest_framework框架后,我们的request是重新封装的Request类

    request.query_params存放的是我们get请求的参数

    request.data存放的是我们所有的数据,包括post请求的以及put,patch请求

    相比原来的Django的request,我们现在的request更加精简,清晰了

    由于我们写的视图可能对多个表进行增删改查,就导致我们的视图特别多重复的代码

    所以我们需要封装一下。

    第一次封装

    因为代码中除了序列化器不同以及获取的queryset对象不同,其他的都类似。所有我们它相同的代码封装出来,提高代码的复用性。

      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("删除的书籍不存在")
    

      第一次封装

    from django.shortcuts import render
    from rest_framework.views import APIView
    from djangoDemo.models import Book
    from .serializers import BookSerializer
    from rest_framework.response import Response
    
    
    # queryset不同
    # 序列化器不同
    # def get():
    # def post():
    
    class GenericAPIView(APIView):
        queryset = None
        serializer_class = None
    
        def get_queryset(self):
            # 放到缓存中再拿出来时就需要我们用all()来获取,这是Django机制导致的
            return self.queryset.all()
    
        def get_serializer(self, *args, **kwargs):
            return self.serializer_class(*args, **kwargs)
    
    
    class ListModelMixin(object):
        def list(self, request):
            # 调用外部的get方法
            # 执行父类的方法
            queryset = self.get_queryset()
            # 实例化序列化器
            ser_obj = self.get_serializer(queryset, many=True)
            return Response(ser_obj.data)
    
    
    class CreateModelMixin(object):
        def create(self, request):
            ser_obj = self.get_serializer(data=request.data)
            if ser_obj.is_valid():
                ser_obj.save()
                # 校验过的数据存放在validated_data中
                return Response(ser_obj.validated_data)
            return Response(ser_obj.errors)
    
    
    class RetrieveModelMixin(object):
        def retrieve(self, request, id):
            book_obj = self.get_queryset().filter(id=id).first()
            ser_obj = BookSerializer(book_obj)
            return Response(ser_obj.data)
    
    
    class UpdateModelMixin(object):
        def update(self, request, id):
            book_obj = self.get_queryset().filter(id=id).first()
            ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
            if ser_obj.is_valid():
                ser_obj.save()
                # 去反序列化以后的数据中去找到并返回
                return Response(ser_obj.validated_data)
            return Response(ser_obj.errors)
    
    
    class DestroyModelMixin(object):
        def destroy(self, request, id):
            book_obj = self.get_queryset().filter(id=id).first()
            if not book_obj:
                return Response('删除的数据不存在')
            book_obj.delete()
            return Response('')
    
    
    class BookView(GenericAPIView, ListModelMixin, CreateModelMixin):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
        def get(self, request):
            # 封装ListModelMixin类以后的执行过程
            return self.list(request)
    
            # 只封装GenericAPIView类的执行过程
            # # 调用外部的get方法
            # # 执行父类的方法
            # queryset = self.get_queryset()
            # # 实例化序列化器
            # ser_obj = self.get_serializer(queryset, many=True)
            # return Response(ser_obj.data)
    
            # 没封装之前
            # book_queryset = Book.objects.all()
            # 用序列化器进行序列化
            # ser_obj = BookSerializer(book_queryset, many=True)
            # 通过点data来获取数据
            # return Response(ser_obj.data)
    
        # 没封装前的post执行过程
        # def post(self, request):
        #     # 获取从前端传递过来的值
        #     book_obj = request.data
        #     # data=book_obj就是反序列化时的对象数据
        #     ser_obj = BookSerializer(data=book_obj)
        #     if ser_obj.is_valid():
        #         ser_obj.save()
        #         # 反序列化以后的数据放在validated_data中
        #         return Response(ser_obj.validated_data)
        #     # 如果校验不成功则返回错误信息
        #     return Response(ser_obj.errors)
    
        # 继承CreateModelMixin类后的post执行过程
        def post(self, request):
            return self.create(request)
    
    
    class BookEditView(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    
        def get(self, request, id):
            # book_obj = Book.objects.filter(id=id).first()
            # ser_obj = BookSerializer(book_obj)
            # return Response(ser_obj.data)
            return self.retrieve(request, id)
    
        def put(self, request, id):
            # book_obj = Book.objects.filter(id=id).first()
            # ser_obj = BookSerializer(instance=book_obj, data=request.data, partial=True)
            # if ser_obj.is_valid():
            #     ser_obj.save()
            #     # 去反序列化以后的数据中去找到并返回
            #     return Response(ser_obj.validated_data)
            # return Response(ser_obj.errors)
            return self.update(request, id)
    
        def delete(self, request, id):
            # book_obj = Book.objects.filter(id=id).first()
            # if not book_obj:
            #     return Response('删除的数据不存在')
            # book_obj.delete()
            # return Response('')
            return self.destroy(request, id)

    第二次封装

    # 我们把继承的类封装了一下
    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):
            # 封装ListModelMixin类以后的执行过程
            return self.list(request)
     
        # 继承CreateModelMixin类后的post执行过程
        def post(self, request):
            return self.create(request)
     
     
    class BookEditView(RetrieveUpdateDestroyAPIView):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
     
        def get(self, request, id):
            return self.retrieve(request, id)
     
        def put(self, request, id):
            return self.update(request, id)
     
        def delete(self, request, id):
            return self.destroy(request, id)

     第三次封装

    我们可不可以把这两个视图合并成一个视图呢~~~框架给我们提供了一个路由传参的方法~~

    actions这个默认参数其实就是我们路由可以进行传参了~~~

    下面这个循环~可以看出~我们要传的参数是一个字段~key应该是我们的请求方式,value应该对应我们处理的方法~

    这样我们每个视图就不用在写函数了~因为已经和内部实现的函数相对应了~

      路由urls.py

    from django.conf.urls import url, include
    from .views import BookView, BookEditView, BookModelView
    # 帮助我们生成带参数的路由
    from rest_framework.routers import DefaultRouter
    # 实例化DefaultRouter对象
    router = DefaultRouter()
    # 注册我们的路由以及视图
    router.register(r'^book', BookModelView)
    
    
    urlpatterns = [
        url(r'^book$', BookView.as_view()),
        # url(r'^book/(?P<id>d+)', BookEditView.as_view()),
        url(r'^book$', BookModelView.as_view({"get": "list", "post": "create"})),
        # url(r'^book/(?P<pk>d+)', BookModelView.as_view({"get": "retrieve", "put": "update", "delete": "destroy"})),
        
    ]
    
    urlpatterns += router.urls
    

      第三次封装

    ViewSetMixin  重写了as_view()方法

    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from djangoDemo.models import Book
    from .serializers import BookSerializer
    from rest_framework.viewsets import ViewSetMixin
    
    
    from rest_framework import views  # APIView
    from rest_framework import viewsets
    from rest_framework import generics
    from rest_framework import mixins
    
    
    # 自定义了一个类,
    class ModelViewSet(ViewSetMixin, ListModelMixin, CreateModelMixin, UpdateModelMixin, DestroyModelMixin):
        pass
    
    
    # 然后继承它
    class BookModelView(ModelViewSet):
        queryset = Book.objects.all()
        serializer_class = BookSerializer
    

      由于第三次封装所以路由发生了改变:

    from django.conf.urls import url, include
    from .views import BookView, BookEditView, BookModelView
    
    urlpatterns = [
        url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})),
        url(r'^book/(?P<pk>d+)/',
            BookModelView.as_view({"get": "list", "post": "create", "put": "update", "delete": "destroy"})),
    ]
    

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

    看看我们的继承顺序

    DRF的路由

    路由

    from django.conf.urls import url, include
    from .views import BookView, BookEditView, BookModelView
    
    # 帮我们生成带参数的路由(我们原本是不能传递参数的在路由中)
    from rest_framework.routers import DefaultRouter
    
    # 实例化DefaultRouter对象
    router = DefaultRouter()
    
    # 注册我们的路由以及视图
    router.register(r'book', BookModelView)
    
    
    urlpatterns = [
        # url(r'^book/$', BookView.as_view()),
        # url(r'^book/(?P<pk>d+)/', BookEditView.as_view()),
        # url(r'^book/$', BookModelView.as_view({"get": "list", "post": "create"})),
        # url(r'^book/(?P<pk>d+)/',
            # BookModelView.as_view({"get": "list", "post": "create", "put": "update", "delete": "destroy"})),
    ]
    
    urlpatterns += router.urls
    

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

      

  • 相关阅读:
    Jquery 添加插件
    后台添加前台标签
    jQuery.validate 中文API
    jquery validate 详解二
    jquery validate 详解一
    System.Collections里的一些接口
    C#中 Reference Equals, == , Equals的区别
    关于iOS原生条形码扫描,你需要注意的两三事
    layoutSubviews何时调用的问题(转)
    layoutSubviews总结
  • 原文地址:https://www.cnblogs.com/wjs521/p/9976307.html
Copyright © 2020-2023  润新知