zoukankan      html  css  js  c++  java
  • Django Restful Framework【第五篇】分页、视图、路由、渲染器

    一、分页

    试问如果当数据量特别大的时候,你是怎么解决分页的?

    • 方式a、记录当前访问页数的数据id
    • 方式b、最多显示120页等
    • 方式c、只显示上一页,下一页,不让选择页码,对页码进行加密

    1、基于limit offset 做分页

    from rest_framework.pagination import LimitOffsetPagination
    urls.py
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^app01/(?P<version>[v1|v2]+)/', include('app01.urls'))
    
    ]
    

    app01.url

    urlpatterns = [
        url(r'^index1/', views.IndexView1.as_view()),
        url(r'^index2/', views.IndexView2.as_view()),
        url(r'^index3/', views.IndexView3.as_view()),
        url(r'^index4/', views.IndexView4.as_view()),
        url(r'^index5/', views.IndexView5.as_view()),
    
    ]
    

    views.py

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from app01.serializes.myserializes import MySerializes
    from rest_framework.pagination import LimitOffsetPagination
    from app01 import models
    
    # =========== 可以自己进行自定制分页,基于limitoffset===================
    class P1(LimitOffsetPagination):
        max_limit = 3  # 最大限制默认是None
        default_limit =2  # 设置每一页显示多少条
        limit_query_param = 'limit'  # 往后取几条
        offset_query_param = 'offset'  # 当前所在的位置
    
    class IndexView2(APIView):
        #使用http://127.0.0.1:8080/app01/v1/index2/?offset=2&limit=4可进行判断
        def get(self,request,*args,**kwargs):
            user_list = models.UserInfo.objects.all()
            p1 = P1()#注册分页
            page_user_list = p1.paginate_queryset(queryset=user_list,request=request,view=self)
            print('打印的是分页的数据',page_user_list)
            ser = MySerializes(instance=page_user_list,many=True)  #可允许多个
            # return Response(ser.data) #不含上一页下一页
            return p1.get_paginated_response(ser.data)
    
    =======================也可以用下面这种形式===========
    class BaseResponse(object):
        def __init__(self,code=1000,data=None,error=None):
            self.code = code
            self.data = data
            self.error = error
    class IndexView(views.APIView):
        '''第二种类表示的方式'''
        def get(self,request,*args,**kwargs):
            ret = BaseResponse()
            try:
                user_list = models.UserInfo.objects.all()
                p1 = P1()
                page_user_list = p1.paginate_queryset(queryset=user_list,request=request,view=self)
                ser = IndexSerializer(instance=page_user_list,many=True)
                ret.data = ser.data
                ret.next = p1.get_next_link()
            except Exception as e:
                ret.code= 1001
                ret.error = 'xxxx错误'
            return Response(ret.__dict__)
    

     

    2、基于页码的分页

    from rest_framework.pagination import PageNumberPagination
    # ======================基于页码实现的分页==============
    class P2(PageNumberPagination):
        #默认每页显示的数据条数
        page_size = 2
        #获取url参数中设置的每页显示数据条数
        page_size_query_param = 'size'
        #获取url中传入的页码key
        page_query_param = 'page'
        #最大支持的每页显示的数据条数
        max_page_size = 5
    
    class IndexView3(APIView):
        #使用http://127.0.0.1:8080/app01/v1/index3/?page=1&page_size=1可进行判断
        def get(self,request,*args,**kwargs):
            user_list = models.UserInfo.objects.all()
            #实例化分页对象,获取数据库中的分页数据
            p2 = P2()
            print(p2.page_size_query_description)
            page_user_list = p2.paginate_queryset(queryset=user_list,request=request,view=self)
            print('打印的是分页的数据',page_user_list)
    
            #序列化对象
            ser = MySerializes(instance=page_user_list,many=True)  #可允许多个
    
            #生成分页和数据
            # return Response(ser.data) #不含上一页下一页
            return p2.get_paginated_response(ser.data)

    3、基于Cursor的分页

         2可能存在性能问题,如果用户吧page给改的很大,查询速度就会很慢。还有一种页码加密的方式,

    # =====================基于Cursor的分页============
    class P3(CursorPagination):
        # URL传入的游标参数
        cursor_query_param = 'cursor'
        # 默认每页显示的数据条数
        page_size = 2
        # URL传入的每页显示条数的参数
        page_size_query_param = 'size'
        # 每页显示数据最大条数
        max_page_size = 3
    
        # 根据ID从大到小排列
        ordering = "id"
        
    class IndexView4(APIView):
        #使用http://127.0.0.1:8080/app01/v1/index4/?cursor=cj0xJnA9NA%3D%3D&size=3可进行判断
        def get(self,request,*args,**kwargs):
            user_list = models.UserInfo.objects.all().order_by('-id')
            p3 = P3()#注册分页
            page_user_list = p3.paginate_queryset(queryset=user_list,request=request,view=self)
            print('打印的是分页的数据',page_user_list)
            ser = MySerializes(instance=page_user_list,many=True)  #可允许多个
            # return Response(ser.data) #不含上一页下一页
            return p3.get_paginated_response(ser.data)
    

      

    二、视图

    写视图函数可继承的几个类,我们以前经常用到的是APIView,现在我们来了解一下其他的类,其中1、3、4用到的最多

    需要导入的类

    from rest_framework.views import APIView
    from rest_framework.generics import GenericAPIView
    from rest_framework.viewsets import GenericViewSet
    from rest_framework.viewsets import ModelViewSet

    1、APIView

    class IndexView2(APIView):
        def get(self,request,*args,**kwargs):
            user_list = models.UserInfo.objects.all()
            ser = MySerializes(instance=user_list,many=True)
            return Response(ser.data)

    2、GenericAPIView(APIView)

    from rest_framework.response import Response
    from rest_framework.generics import GenericAPIView
    from app01 import models
    from app01.serializes.myserializes import MySerializes
    from rest_framework.pagination import LimitOffsetPagination
    class P1(LimitOffsetPagination):
        max_limit = 3  # 最大限制默认是None
        default_limit =2  # 设置每一页显示多少条
        limit_query_param = 'limit'  # 往后取几条
        offset_query_param = 'offset'  # 当前所在的位置
    
    class IndexView1(GenericAPIView):
        queryset = models.UserInfo.objects.all()
        serializer_class = MySerializes
        pagination_class = P1
        def get(self,request,*args,**kwargs):
            user_list = self.get_queryset()
            p1 = P1()  #注册分页
            data = p1.paginate_queryset(queryset=user_list,request=request,view=self)  #获取分页的数据
            ser = self.get_serializer(instance=data,many=True) #序列化
            return Response(ser.data)
    

      

    3、 GenericViewSet(ViewSetMixin, generics.GenericAPIView)

    增
        POST
        /users/
    删
        DELETE
        /users/1/
    改   #全部修改
        PUT
        /users/1/
        #局部修改
        patch
        /users/1/
    查
        GET
        /users/ 
        GET
        /users/1/
    在GET请求的时候如果带ID说明查一条,如果不带则查所有

    原始的

    urls.py
    urlpatterns = [
    
        url(r'^index/$', views.IndexView.as_view()),
        url(r'^index/(?P<pk>d+)$', views.IndexView.as_view()),
    ]
    views.py
    class IndexView(views.APIView):
    
        def get(self,request,*args,**kwargs):
            pk = kwargs.get('pk')
            if pk:
                pass # 获取单条信息
            else:
                pass # 获取列表信息
    
        def post(self,request,*args,**kwargs):
            pass
    
        def put(self,request,*args,**kwargs):
            pass
    
        def patch(self,request,*args,**kwargs):
            pass
    
        def delete(self,request,*args,**kwargs):
                    pass
    

      

    用了GenericViewSet这种方式的时候注意url变了

    urls.py
    urlpatterns = [
        url(r'^index3/$', views.IndexView3.as_view({'get': 'list','post':'create'})),
        url(r'^index3/(?P<pk>d+)/$', views.IndexView3.as_view({'get':'retrieve'})),
       
    ]
    views.py
    class IndexView3(GenericViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = MySerializes
        pagination_class = P1
    
        def list(self,request,*args,**kwargs):
            #获取列表信息
            return Response('...')
    
        def retrieve(self,request,*args,**kwargs):
            #获取单条数据
            return Response('xxx')
    

      

    4、 ModelViewSet(mixins.CreateModelMixin,mixins.RetrieveModelMixin,mixins.UpdateModelMixin,mixins.DestroyModelMixin,mixins.ListModelMixin,GenericViewSet)

    利用ModelViewSet增删改查不用自己写了,内部把增删改查都干了,当满足不了需求的时候我们也可以自定制

    urls.py
    urlpatterns = [
    
        url(r'^index4/', views.IndexView4.as_view({'get': 'list','post':'create'})),  #获取数据和添加数据
        url(r'^index4.(?P<format>[a-z0-9]+)/', views.IndexView4.as_view({'get': 'list','post':'create'})), #.json想让页面上显示成json格式
        url(r'^index4/(?P<pk>d+)/', views.IndexView4.as_view({'get': 'retrieve', 'delete': 'destroy','put':'partial_update'})), #查看单条,删除,修改数据
        url(r'^index4(?P<pk>d+).(?P<format>[a-z0-9]+)/', views.IndexView4.as_view({'get': 'retrieve', 'delete': 'destroy','put':'partial_update'})),
    
    ]
    views.py
    注意啦:用ModelSerializer这种方法必须要用IndexSerializer(ModelSerializer)这种方式序列化
    class P2(PageNumberPagination):
        page_size = 3  #每一页显示的条数
        page_query_param = 'page' #获取参数中传入的页码
        page_size_query_param = 'size' #获取url参数中每页显示的数据条数
    
        max_page_size = 5
    
    class IndexSerializer(ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    class IndexView4(ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2
    

      

    自定制

    基于ModelViewSet自定制
    class P2(PageNumberPagination):
        page_size = 3  #每一页显示的条数
        page_query_param = 'page' #获取参数中传入的页码
        page_size_query_param = 'size' #获取url参数中每页显示的数据条数
    
        max_page_size = 5
    
    class IndexSerializer(ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    class IndexView4(ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2
    
        def list(self, request, *args, **kwargs):
            '''获取get请求的所有'''
            pass
    
        def retrieve(self, request, *args, **kwargs):
            '''查看单条数据'''
            pass
        def destroy(self, request, *args, **kwargs):
            '''删除DELETE'''
            pass
        def create(self, request, *args, **kwargs):
            '''添加数据POST'''
            pass
        def update(self, request, *args, **kwargs):
            '''全部修改PUT'''
            pass
        def partial_update(self, request, *args, **kwargs):
            '''局部修改PATCH'''
            pass
    

      

    继承关系

     

    三、路由

    第一类:自定义路由

    # http://127.0.0.1:8000/api/v1/auth/
    url(r'^auth/$', views.AuthView.as_view()),
    # http://127.0.0.1:8000/api/v1/auth.json # 想要让页面显示json格式
    url(r'^auth.(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
    # http://127.0.0.1:8000/api/v1/auth/1/
    url(r'^auth/(?P<pk>d+)/$', views.AuthView.as_view()),
    # http://127.0.0.1:8000/api/v1/auth/1.json
    url(r'^auth/(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.AuthView.as_view()),
    class AuthView(views.APIView):
    
        def get(self,request,*args,**kwargs):
            return Response('...')

    第二类:半自动路由

    url(r'^index/$', views.IndexView.as_view({'get':'list','post':'create'})),
    url(r'^index.(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'list','post':'create'})),
    url(r'^index/(?P<pk>d+)/$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
    url(r'^index(?P<pk>d+).(?P<format>[a-z0-9]+)$', views.IndexView.as_view({'get':'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
    
    class IndexView(viewsets.ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2

    第三类:全自动路由,会自动生成四个url

    router = DefaultRouter()
    router.register('index',views.IndexViewSet)
    urlpatterns = [
        url(r'^', include(router.urls)),
    ]
    
    
    class IndexViewSet(viewsets.ModelViewSet):
        queryset = models.UserInfo.objects.all()
        serializer_class = IndexSerializer
        pagination_class = P2
        
        
        
    class IndexSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"

     

    四、渲染器

    根据 用户请求URL 或 用户可接受的类型,筛选出合适的 渲染组件。
    用户请求URL:

    • http://127.0.0.1:8000/test/?format=json
    • http://127.0.0.1:8000/test.json

    用户请求头:

    • Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8

    1、. json

    访问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/ 
    urls.py
    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()),
    ]
    
    urls.py
    views.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    
    from rest_framework.renderers import JSONRenderer
    
    from .. import models
    
    
    class TestSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    
    class TestView(APIView):
        renderer_classes = [JSONRenderer, ]
    
        def get(self, request, *args, **kwargs):
            user_list = models.UserInfo.objects.all()
            ser = TestSerializer(instance=user_list, many=True)
            return Response(ser.data)
    

      

    2、.表格

    访问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/ 
    views.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    
    from rest_framework.renderers import AdminRenderer
    
    from .. import models
    
    
    class TestSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    
    class TestView(APIView):
        renderer_classes = [AdminRenderer, ]
    
        def get(self, request, *args, **kwargs):
            user_list = models.UserInfo.objects.all()
            ser = TestSerializer(instance=user_list, many=True)
            return Response(ser.data)
    

      

    3、 Form表单

    访问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/ 
    views.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    
    from rest_framework.renderers import JSONRenderer
    from rest_framework.renderers import AdminRenderer
    from rest_framework.renderers import HTMLFormRenderer
    
    from .. import models
    
    
    class TestSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    
    class TestView(APIView):
        renderer_classes = [HTMLFormRenderer, ]
    
        def get(self, request, *args, **kwargs):
            user_list = models.UserInfo.objects.all().first()
            ser = TestSerializer(instance=user_list, many=False)
            return Response(ser.data)
    

      

    4、 自定义显示模板

    访问URL:

    • http://127.0.0.1:8000/test/?format=html
    • http://127.0.0.1:8000/test.html
    • http://127.0.0.1:8000/test/ 
    urls.py
    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()),
    ]
    views.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    from rest_framework.renderers import TemplateHTMLRenderer
    
    from .. import models
    
    
    class TestSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    
    class TestView(APIView):
        renderer_classes = [TemplateHTMLRenderer, ]
    
        def get(self, request, *args, **kwargs):
            user_list = models.UserInfo.objects.all().first()
            ser = TestSerializer(instance=user_list, many=False)
            return Response(ser.data, template_name='user_detail.html')
    userdetail.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
        {{ user }}
        {{ pwd }}
        {{ ut }}
    </body>
    </html>
    

      

    5、浏览器格式API+JSON

    访问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/ 
    views.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    
    from rest_framework.renderers import JSONRenderer
    from rest_framework.renderers import BrowsableAPIRenderer
    
    from .. import models
    
    
    class TestSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.UserInfo
            fields = "__all__"
    
    
    class CustomBrowsableAPIRenderer(BrowsableAPIRenderer):
        def get_default_renderer(self, view):
            return JSONRenderer()
    
    
    class TestView(APIView):
        renderer_classes = [CustomBrowsableAPIRenderer, ]
    
        def get(self, request, *args, **kwargs):
            user_list = models.UserInfo.objects.all().first()
            ser = TestSerializer(instance=user_list, many=False)
            return Response(ser.data, template_name='user_detail.html')
    

      

    注意:如果同时多个存在时,自动根据URL后缀来选择渲染器。

     
     
  • 相关阅读:
    Centos 端口被占用,kill被占用的进程
    Centos7 docker安装GitLab
    MongoDB 3.6.1集群部署
    MySql时区修改
    Springboot默认定时任务——Scheduled注解
    Nacos Docker集群部署
    docker-compose使用
    docker部署redis集群
    设置Redis集群访问密码(不停机设置)
    AWS SNS 创建 订阅 发布
  • 原文地址:https://www.cnblogs.com/xiaohema/p/8456967.html
Copyright © 2011-2022 走看看