• DAY101


    一、视图组件

    1.基本视图

    class Books(APIView):
        def get(self, request, *args, **kwargs):
            books = models.Book.objects.all()
            response = {'status': 200, 'msg': '查询成功', 'data': None}
            ret = BooksSerializer(books, many=True)
            response['data'] = ret.data
            return JsonResponse(response, safe=False)
    
        def post(self, request, *args, **kwargs):
            response = {'status': 200, 'msg': '创建成功', 'data': None, 'error': None}
            ret = BooksSerializer(data=request.data)
            if ret.is_valid():
                ret.save()
                response['data'] = ret.data
            else:
                response['error'] = ret.errors
            return JsonResponse(ret.data, safe=False)
    
    
    class BooksDetail(APIView):
        def get(self, request, id, *args, **kwargs):
            books = models.Book.objects.filter(pk=id).first()
            response = {'status': 200, 'msg': '查询成功', 'data': None}
            if books:
                ret = BooksSerializer(books, many=False)
                response['data'] = ret.data
            else:
                response['msg'] = '查无此信息'
            return JsonResponse(response, safe=False)
    
        def put(self, request, id, *args, **kwargs):
            books = models.Book.objects.filter(pk=id).first()
            response = {'status': 200, 'msg': '更新成功', 'data': None, 'error': None}
            ret = BooksSerializer(data=request.data, instance=books)
            if ret.is_valid():
                ret.save()
                response['data'] = ret.data
            else:
                response['error'] = ret.errors
            return JsonResponse(ret.data, safe=False)
    
        def delete(self, request, id, *args, **kwargs):
            books = models.Book.objects.filter(pk=id).first()
            response = {'status': 200, 'msg': '删除成功', 'data': None}
            ret = BooksSerializer(books, many=False)
            response['data'] = ret.data
            books.delete()
            return JsonResponse(response, safe=False)
    

    2.利用mixin类简化视图

    基本视图中的有些代码可以进一步简化,比如说表名和序列化对象可以用一个

    from rest_framework.mixins import ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin,DestroyModelMixin
    from rest_framework.generics import GenericAPIView
    
    
    class Books(GenericAPIView, ListModelMixin, CreateModelMixin):
        # queryset和serializer_class是GenericAPIView定义必须要写的
        queryset = models.Book.objects.all()
        serializer_class = BooksSerializer
    
        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 BooksDetail(GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
        queryset = models.Book.objects.all()
        serializer_class = BooksSerializer
    	# 必须传pk,因为这是RetrieveModelMixin等调用的GenericAPIView方法规定的
        def get(self, request, pk):
            return self.retrieve(request, pk)
    
        def put(self, request, pk):
            return self.update(request, pk)
    
        def delete(self, request, pk):
            return self.destroy(request, pk)
    

    2.1 mixin类源码分析

    # ListModelMixin
    # 以ListModelMixin举例,它实际上是,把我们写的基本视图中的代码进行了封装,而对于用户只要继承该类,并且引用就行了
    class ListModelMixin(object):
        """
        List a queryset.
        """
        def list(self, request, *args, **kwargs):
            queryset = self.filter_queryset(self.get_queryset())
    
            page = self.paginate_queryset(queryset)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(queryset, many=True)
            return Response(serializer.data)
    

    2.2 GenericAPIView源码分析

    # GenericAPIView
    # mixin类中的一些方法是调用GenericAPIView中的方法,所以视图类如果继承mixin类,就必须也继承GenericAPIView
    # 由于GenericAPIView已经继承了APIView,所以视图不必再继承APIView了
    class GenericAPIView(views.APIView):
        queryset = None
        serializer_class = None
    
        lookup_field = 'pk'
        lookup_url_kwarg = None
    
        filter_backends = api_settings.DEFAULT_FILTER_BACKENDS
    
        pagination_class = api_settings.DEFAULT_PAGINATION_CLASS
    
        # get_queryset:获得视图类里的queryset表格的所有数据
        def get_queryset(self):
            queryset = self.queryset
            # 判断queryset是否是QuerySet实例化后的对象
            if isinstance(queryset, QuerySet):
                # 如果是QuerySet对象,就再次all()
                queryset = queryset.all()
            return queryset
    	
        # get_object:获得单条数据
        def get_object(self):
            # 对所及数据进行过滤
            queryset = self.filter_queryset(self.get_queryset())
    		
            ........
            
            filter_kwargs = {self.lookup_field: self.kwargs[lookup_url_kwarg]}
            obj = get_object_or_404(queryset, **filter_kwargs)
    
            self.check_object_permissions(self.request, obj)
    
            return obj
    	
        # get_serializer:返回序列化对象
        def get_serializer(self, *args, **kwargs):
            serializer_class = self.get_serializer_class()
            kwargs['context'] = self.get_serializer_context()
            return serializer_class(*args, **kwargs)
    
        # get_serializer_class:获得视图里的序列化对象
        def get_serializer_class(self):
    		
            ........
    
            return self.serializer_class
    
        def get_serializer_context(self):
    		........
    
        def filter_queryset(self, queryset):
    		........
    
        @property
        def paginator(self):
    		........
    
        def paginate_queryset(self, queryset):
    		........
    
        def get_paginated_response(self, data):
    		........
    

    3.利用generice类简化代码

    虽然已经简化了代码,但是get和post等方法的代码还是重复了,都是一条代码,还可以再一步简略

    from rest_framework.generics import ListCreateAPIView, RetrieveUpdateDestroyAPIView
    
    
    class Books(ListCreateAPIView):
        queryset = models.Book.objects.all()
        serializer_class = BooksSerializer
    
    
    class BooksDetail(RetrieveUpdateDestroyAPIView):
        queryset = models.Book.objects.all()
        serializer_class = BooksSerializer
    

    3.1 ListCreateAPIView源码分析

    # ListCreateAPIView:其实是对mixins类的进一步封装,这样视图里就不需用写get和post了,只要继承ListCreateAPIView就可以,RetrieveUpdateDestroyAPIView也是一样的
    class ListCreateAPIView(mixins.ListModelMixin,
                            mixins.CreateModelMixin,
                            GenericAPIView):
        def get(self, request, *args, **kwargs):
            return self.list(request, *args, **kwargs)
    
        def post(self, request, *args, **kwargs):
            return self.create(request, *args, **kwargs)
    

    4.使用ModelViewSet

    进一步简化代码后,我们发现,两个视图的代码变得一样了,那么可不可以更进一步封装,drf提供了一个方法可以把两个视图合并。

    url(r'^books/',views.Books.as_view({'get':'list','post':'create'})),
    url(r'^booksdetail/(?P<pk>d+)', views.Books.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
    
    from rest_framework.viewsets import ModelViewSet
    
    class Books(ModelViewSet):
        queryset = models.Book.objects.all()
        serialzizer_class = BooksSerializer
    

    4.1ModelViewSet源码分析

    # 第一步
    # ModelViewSet
    # 其实是对所有的mixins类继承
    # GenericViewSet才是关键
    class ModelViewSet(mixins.CreateModelMixin,
                       mixins.RetrieveModelMixin,
                       mixins.UpdateModelMixin,
                       mixins.DestroyModelMixin,
                       mixins.ListModelMixin,
                       GenericViewSet):
        pass
    
    
    # 第二步
    # GenericViewSet
    # 是对ViewSetMixin和GenericAPIView的继承
    # 由于继承了GenericAPIView,而GenericAPIView已经继承了APIView,所以视图不必再继承APIView
    class GenericViewSet(ViewSetMixin, generics.GenericAPIView):
        pass
    
    # 第三步
    # ViewSetMixin
    # ViewSetMixin是对as_view的重写
    class ViewSetMixin(object):
       @classonlymethod
        def as_view(cls, actions=None, **initkwargs):
            # actions={'get':'retrieve','put':'update','delete':'destroy'}
            # 是路由层传来的参数
            cls.name = None
            cls.description = None
            cls.suffix = None
            cls.detail = None
            cls.basename = None
            
            .......
        	
            def view(request, *args, **kwargs):
                self = cls(**initkwargs)
    
                self.action_map = actions
    			# 对action循环
                # 请求方式:method='get'  对应方法:action='list'
                for method, action in actions.items():
                    # 把action的,也就是list的内存地址赋给了handler
                    handler = getattr(self, action)
                    # 把handler的,也就是list的内存地址赋给了method
                    # 也就是说,执行get方法就是执行list方法
                    setattr(self, method, handler)
    
                if hasattr(self, 'get') and not hasattr(self, 'head'):
                    self.head = self.get
    
                self.request = request
                self.args = args
                self.kwargs = kwargs
    
                return self.dispatch(request, *args, **kwargs)
    
            update_wrapper(view, cls, updated=())
    
            update_wrapper(view, cls.dispatch, assigned=())
    
            view.cls = cls
            view.initkwargs = initkwargs
            view.actions = actions
            return csrf_exempt(view)
    

    二、路由控制

    1.自定义路由

    url(r'^books/', views.Books.as_view()),
    url(r'^booksdetail/(?P<pk>d+)', views.BooksDetail.as_view()),
    
    class Books(APIView):
        def get(self, request, *args, **kwargs):
            books = models.Book.objects.all()
            response = {'status': 200, 'msg': '查询成功', 'data': None}
            ret = BooksSerializer(books, many=True)
            response['data'] = ret.data
            return JsonResponse(response, safe=False)
    
        def post(self, request, *args, **kwargs):
            response = {'status': 200, 'msg': '创建成功', 'data': None, 'error': None}
            ret = BooksSerializer(data=request.data)
            if ret.is_valid():
                ret.save()
                response['data'] = ret.data
            else:
                response['error'] = ret.errors
            return JsonResponse(ret.data, safe=False)
    
    
    class BooksDetail(APIView):
        def get(self, request, id, *args, **kwargs):
            books = models.Book.objects.filter(pk=id).first()
            response = {'status': 200, 'msg': '查询成功', 'data': None}
            if books:
                ret = BooksSerializer(books, many=False)
                response['data'] = ret.data
            else:
                response['msg'] = '查无此信息'
            return JsonResponse(response, safe=False)
    
        def put(self, request, id, *args, **kwargs):
            books = models.Book.objects.filter(pk=id).first()
            response = {'status': 200, 'msg': '更新成功', 'data': None, 'error': None}
            ret = BooksSerializer(data=request.data, instance=books)
            if ret.is_valid():
                ret.save()
                response['data'] = ret.data
            else:
                response['error'] = ret.errors
            return JsonResponse(ret.data, safe=False)
    
        def delete(self, request, id, *args, **kwargs):
            books = models.Book.objects.filter(pk=id).first()
            response = {'status': 200, 'msg': '删除成功', 'data': None}
            ret = BooksSerializer(books, many=False)
            response['data'] = ret.data
            books.delete()
            return JsonResponse(response, safe=False)
    

    2.半自动路由(需继承ModelViewSet)

    url(r'^books/',views.Books.as_view({'get':'list','post':'create'})),
    url(r'^booksdetail/(?P<pk>d+)', views.Books.as_view({'get':'retrieve','put':'update','delete':'destroy'})),
    
    from rest_framework.viewsets import ModelViewSet
    
    class Books(ModelViewSet):
        queryset = models.Book.objects.all()
        serialzizer_class = BooksSerializer
    

    3.全自动路由

    from django.conf.urls import url,include
    from django.contrib import admin
    from app01 import views
    from rest_framework import routers
    # 生成一个router对象
    router = routers.DefaultRouter()
    # 需要传两个参数,第一个参数就是匹配的路径,第二个参数,是视图类
    router.register('books',views.Books)
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # 不用匹配正则,空字符串就行
        url('',include(router.urls))
    ]
    
    # url('',include(router.urls))会自动创建以下6个URL
    # '^books/$ [name='book-list']'
    # '^books.(?P<format>[a-z0-9]+)/?$ [name='book-list']'
    # '^books/(?P<pk>[^/.]+)/$ [name='book-detail']'
    # '^books/(?P<pk>[^/.]+).(?P<format>[a-z0-9]+)/?$ [name='book-detail']'
    # '^$ [name='api-root']'
    # '^.(?P<format>[a-z0-9]+)/?$ [name='api-root']'
    
    from rest_framework.viewsets import ModelViewSet
    
    # 视图一定要是继承ModelViewSet的
    class Books(ModelViewSet):
        queryset = models.Book.objects.all()
        serializer_class = BooksSerializer
    
    

    三、响应器

    1.基本使用

    from rest_framework.renderers import  HTMLFormRenderer,BrowsableAPIRenderer,AdminRenderer,JSONRenderer
    
    class Books(APIView):
        # 局部指定使用
        renderer_classes = [AdminRenderer,]
        
    # setting.py
    # 全局使用
    REST_FRAMEWORK = {
        'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer']
    }
    
    根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件。
    用户请求URL:
        http://127.0.0.1:8000/test/?format=json
        http://127.0.0.1:8000/test.json
                
    显示json格式:JSONRenderer
    
    访问URL:
    
    	http://127.0.0.1:8000/test/?format=json
    	http://127.0.0.1:8000/test.json
    	http://127.0.0.1:8000/test/
     
    默认显示格式:BrowsableAPIRenderer(可以修改它的html文件)
    
    访问URL:
    
    	http://127.0.0.1:8000/test/?format=api
    	http://127.0.0.1:8000/test.api
    	http://127.0.0.1:8000/test/
     
    
    表格方式:AdminRenderer
    
    访问URL:
    
    	http://127.0.0.1:8000/test/?format=admin
    	http://127.0.0.1:8000/test.admin
    	http://127.0.0.1:8000/test/
     
    
    form表单方式:HTMLFormRenderer
    
    访问URL:
    
    	http://127.0.0.1:8000/test/?format=form
    	http://127.0.0.1:8000/test.form
    	http://127.0.0.1:8000/test/
     
    
  • 相关阅读:
    emulate sh
    postmaster.c 中的 ListenAddresses
    PostgreSQL的postmaster的fork动作验证
    NotifyMyFrontEnd 函数背后的数据缓冲区(三)
    对${ZSH_VERSION+set}的验证
    微软正准备一个简易的Rootkit清除方案 助用户打补丁 狼人:
    创新与安全:云计算的两只跷跷板 狼人:
    苹果禁止iPhone黑客访问App Store应用商店 狼人:
    春节不回家 单身留守族“拼饭”“拼玩” 狼人:
    僵尸侵入全球 袭击者或为东欧黑帮 狼人:
  • 原文地址:https://www.cnblogs.com/xvchengqi/p/10133387.html
Copyright © 2020-2023  润新知