文章目錄
7. 分頁
如果有1000萬條數據,怎麼分頁?記錄下結尾的位置,下次檢索,直接跳到那個位置,然後取多少個
a. 分頁,看第n頁,每頁顯示n條數據;(基於PageNumberPagination,最常用)
- 一:自己定義個類,繼承自PageNumberPagination
- 二:直接用PageNumberPagination
from rest_framework.pagination import PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 2 # 每頁的數據條數
page_size_query_param = 'size' # 可以動態設置,這頁展示多少條數據,但在max之下
max_page_size = 5 # 每頁最大顯示數量
page_query_param = 'page' # 查詢某一頁的查詢字段
class Pager1View(APIView):
def get(self,request,*args,**kwargs):
# 獲取所有數據(要給一個排序的順序,進行分頁,不然會報警告)
roles = models.Role.objects.all().order_by('-id')
# 創建分頁對象
# pg = MyPageNumberPagination()
pg = PageNumberPagination()
# 在數據庫中獲取分頁的數據
pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
# queryset = 從數據庫拿到的東西
# request = request
# view = 當前處理數據的視圖,基本上都是self
# 對數據進行序列化
ser = PagerSerialiser(instance=pager_roles, many=True)
#return Response(ser.data) # 直接返回對應數據
# 返回分頁生成器攜帶上下頁鏈接的數據
return pg.get_paginated_response(ser.data)
如下所示,多包括了上下頁鏈接,總共的數量:
{
"count": 16,
"next": "http://127.0.0.1:8000/api/v1/pager1/?page=3",
"previous": "http://127.0.0.1:8000/api/v1/pager1/",
"results": [
{
"id": 3,
"user_type": 3,
"username": "lucy",
"password": "123"
},
{
"id": 4,
"user_type": 4,
"username": "admin",
"password": "admin"
}
]
}
b. 分頁,在某個位置,向後查看n條數據;(基於LimitOffsetPagination)
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3 # 默認展示的數量
limit_query_param = 'limit' # 可查詢的數據條數
offset_query_param = 'offset' # 基於第一條,向後偏移多少個(offset=0代表從第一個開始數)
max_limit = 7 # 在最大顯示多少條
# 視圖處理定義是一樣
class Pager1View(APIView):
def get(self,request,*args,**kwargs):
# 獲取所有數據(要給一個排序的順序,進行分頁,不然會報警告)
roles = models.Role.objects.all().order_by('-id')
# 創建分頁對象
# pg = MyLimitOffsetPagination()
pg = LimitOffsetPagination()
# 在數據庫中獲取分頁的數據
pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
# 對數據進行序列化
ser = PagerSerialiser(instance=pager_roles, many=True)
return Response(ser.data)
# return pg.get_paginated_response(ser.data)
c. 加密分頁,上一頁和下一頁(基於CursorPagination,對頁碼鏈接進行加密,避免惡意操作)。
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.response import Response
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 遊標頁碼值,進行加密後的頁碼字符串
page_size = 2 # 每頁顯示的數據數量
ordering = 'id' # 排序方式('-id'表示按id倒序)
page_size_query_param = 'size' # 設置一個字段,通過url設置查詢這頁顯示多少條數據
max_page_size = None # 每頁最大顯示數量
class Pager1View(APIView):
def get(self,request,*args,**kwargs):
# 獲取所有數據(這個排序順序在上邊的ordering中指定了)
roles = models.Role.objects.all()
# 創建分頁對象
# pg = CursorPagination()
pg = MyCursorPagination()
# 在數據庫中獲取分頁的數據
pager_roles = pg.paginate_queryset(queryset=roles,request=request,view=self)
# 對數據進行序列化
ser = PagerSerialiser(instance=pager_roles, many=True)
# return Response(ser.data)
return pg.get_paginated_response(ser.data)
返回數據如下:
{
"next": "http://127.0.0.1:8000/api/v1/pager3/?cursor=cD00",
"previous": "http://127.0.0.1:8000/api/v1/pager3/?cursor=cj0xJnA9Mw%3D%3D",
"results": [
{
"id": 3,
"user_type": 3,
"username": "lucy",
"password": "123"
},
{
"id": 4,
"user_type": 4,
"username": "admin",
"password": "admin"
}
]
}
8. 視圖
之前都是直接繼承的
APIview
類,大部分東西都是自己寫,當然還有其他的東西可以繼承,
通過簡單配置,實現分頁、序列化等等功能。
a. 過去(Django的CBV模式)
class Pager1View(View):
pass
b. 現在 (rest framework的CBV模式)
class Pager1View(APIView): # View
pass
c. 無用(繼承自APIView的類再次繼承,基本不怎麼用)(View --> APIView --> GenericAPIView)
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.generics import GenericAPIView
class View1View(GenericAPIView): # APIView
queryset = models.Role.objects.all()
serializer_class = PagerSerialiser
pagination_class = PageNumberPagination
def get(self,request,*args,**kwargs):
# 獲取數據
roles = self.get_queryset() # models.Role.objects.all()
# [1, 1000,] [1,10]
pager_roles = self.paginate_queryset(roles)
# 序列化
ser = self.get_serializer(instance=pager_roles,many=True)
return Response(ser.data)
d. 類:GenericViewSet(ViewSetMixin, generics.GenericAPIView)
:添加了不少功能,可以以在類中進行配置的方式,實現某些功能。
- 路由:
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list'})),
# 若繼承自上邊,則as_view方法中進行對應關係的設置,對於請求可以進行方法名的重定義
# key 代表請求過來的method名字, value爲反射到的視圖類中處理get請求的方法名。
- 視圖:
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.viewsets import GenericViewSet
class View1View(GenericViewSet):
queryset = models.Role.objects.all() # 要查詢的字段
serializer_class = PagerSerialiser # 序列化的類
pagination_class = PageNumberPagination # 執行分頁的類
def list(self, request, *args, **kwargs):
# 獲取數據
roles = self.get_queryset() # models.Role.objects.all()
# 進行分頁[1, 1000,] [1,10]
pager_roles = self.paginate_queryset(roles)
# 序列化
ser = self.get_serializer(instance=pager_roles, many=True)
return Response(ser.data)
e. 最強大的類ModelViewSet
,繼承了6個類,增、刪、改、查、局部更新、GenericViewSet
(其中GenericViewSet上邊還有父類,一個實現了as_view --> GenericAPIView --> APIView --> View)
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
"""
A viewset that provides default `create()`, `retrieve()`, `update()`,
`partial_update()`, `destroy()` and `list()` actions.
以上這幾個方法實現增加、獲取(查)、更新(改)、局部更新、刪除、列表操作。
"""
pass
- 路由系統:
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
# 刪改查都是基於對象ID來做的,所以這裏要設置(?P<pk>\d+),使得視圖函數能得到需要操作的對象的指針。
url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)/$', views.View1View.as_view({
'get': 'retrieve',
'delete':'destroy',
'put':'update',
'patch':'partial_update'})),
- 視圖:
from api.utils.serializsers.pager import PagerSerialiser
from rest_framework.viewsets import GenericViewSet,ModelViewSet
from rest_framework.mixins import ListModelMixin,CreateModelMixin
# 在類中配置相應的字段
class View1View(ModelViewSet):
queryset = models.Role.objects.all() # 要查詢的字段
serializer_class = PagerSerialiser # 序列化的類
pagination_class = PageNumberPagination # 執行分頁的類
#**PS**: class View1View(CreateModelMixin,GenericViewSet):
#簡單幾行代碼實現增刪改查等基本功能
總結(使用繼承類):
a. 增刪改查
ModelViewSet
b. 增刪CreateModelMixin
,DestroyModelMixin
,GenericViewSet
c. 複雜邏輯GenericViewSet
或APIView
9. 路由
a.最普通的路由
url(r'^(?P<version>[v1|v2]+)/parser/$', views.ParserView.as_view()),
b. 當繼承ViewSetMixin後,路由在as_view中有了方法映射關係
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
c. 支持的路由格式(是渲染出來顯示,還是純json子字符串,不同的設置方式)
# http://127.0.0.1:8000/api/v1/v1/?format=json
url(r'^(?P<version>[v1|v2]+)/v1/$', views.View1View.as_view({'get': 'list','post':'create'})),
# http://127.0.0.1:8000/api/v1/v1.json
url(r'^(?P<version>[v1|v2]+)/v1\.(?P<format>\w+)$', views.View1View.as_view({'get': 'list','post':'create'})),
url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)/$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
url(r'^(?P<version>[v1|v2]+)/v1/(?P<pk>\d+)\.(?P<format>\w+)$', views.View1View.as_view({'get': 'retrieve','delete':'destroy','put':'update','patch':'partial_update'})),
d. 全自動路由(簡單易用,單個情況最好自己寫,包括所有基本的增刪改查)
#在urls.py中
from api import views
from rest_framework import routers
# 會自動生成對應上邊的四種路由形式
router = routers.DefaultRouter()
router.register(r'xxxxx', views.View1View) # 將視圖函數註冊進去
router.register(r'rt', views.View1View)
# 在urlpatterns中配置
urlpatterns = [
url(r'^(?P<version>[v1|v2]+)/', include(router.urls)),
]
10. 渲染
爲了看json數據的頁面展示效果,基本只需要在
settings
裏邊配置上就行。
from rest_framework.renderers import JSONRenderer,BrowsableAPIRenderer
class TestView(APIView):
# renderer_classes = [JSONRenderer,BrowsableAPIRenderer] # 平時只用這兩個足夠,設置加載配置文件中
def get(self, request, *args, **kwargs):
pass
REST_FRAMEWORK = {
"DEFAULT_RENDERER_CLASSES":[
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
]
}
當然也可以自己定製,根據類的繼承查詢界面的位置,找到原生界面修改界面代碼,打自己公司的廣告等。