zoukankan      html  css  js  c++  java
  • DRF 视图和路由

    Django Rest Feamework 视图和路由

    DRF的视图

    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的一些区别~~当然还有~~后面我们还会说~~

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

    那么我们尝试着来进行封装一下~~

    第一次封装

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

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

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

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

    第三次封装

    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"})),
    ]
    路由urls.py
    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~~系统默认的~~

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

    DRF的路由

    1,自定义路由

    from django.conf.urls import url, include
    from web.views import s11_render
    
    urlpatterns = [
        url(r'^test/$', s11_render.TestView.as_view()),
        url(r'^test.(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view()),
        url(r'^test/(?P<pk>[^/.]+)/$', s11_render.TestView.as_view()),
        url(r'^test/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)$', s11_render.TestView.as_view())
    ]
    urls.py
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .. import models
    
    
    class TestView(APIView):
        def get(self, request, *args, **kwargs):
            print(kwargs)
            print(self.renderer_classes)
            return Response('...')
    views.py

    2,半自动路由

    from django.conf.urls import url, include
    from web.views import s10_generic
    
    urlpatterns = [
        url(r'^test/$', s10_generic.UserViewSet.as_view({'get': 'list', 'post': 'create'})),
        url(r'^test/(?P<pk>d+)/$', s10_generic.UserViewSet.as_view(
            {'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy'})),
    ]
    urls.py
    from rest_framework.viewsets import ModelViewSet
    from rest_framework import serializers
    from .. import models
    
    
    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    
    class UserViewSet(ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = UserSerializer
    views.py

    3,全自动路由

    from django.conf.urls import url, include
    from rest_framework import routers
    from web.views import s10_generic
    
    
    router = routers.DefaultRouter()
    router.register(r'users', s10_generic.UserViewSet)
    
    urlpatterns = [
        url(r'^', include(router.urls)),
    ]
    urls.py
    from rest_framework.viewsets import ModelViewSet
    from rest_framework import serializers
    from .. import models
    
    
    class UserSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    
    class UserViewSet(ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = UserSerializer
    views.py
  • 相关阅读:
    CodeForces Gym 100935G Board Game DFS
    CodeForces 493D Vasya and Chess 简单博弈
    CodeForces Gym 100935D Enormous Carpet 快速幂取模
    CodeForces Gym 100935E Pairs
    CodeForces Gym 100935C OCR (水
    CodeForces Gym 100935B Weird Cryptography
    HDU-敌兵布阵
    HDU-Minimum Inversion Number(最小逆序数)
    七月馒头
    非常可乐
  • 原文地址:https://www.cnblogs.com/peng104/p/10140828.html
Copyright © 2011-2022 走看看