1. 程式人生 > >Django Restful Framework【第五篇】分頁、視圖、路由、渲染器

Django Restful Framework【第五篇】分頁、視圖、路由、渲染器

framework 增刪改查 format conf apn register ali dmi elf

一、分頁

試問如果當數據量特別大的時候,你是怎麽解決分頁的?

  • 方式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後綴來選擇渲染器。

Django Restful Framework【第五篇】分頁、視圖、路由、渲染器