06-Django REST framwork 板塊(07-分頁、08-視圖、路由、09-渲染)

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. 複雜邏輯 GenericViewSetAPIView


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',
	]
}

當然也可以自己定製,根據類的繼承查詢界面的位置,找到原生界面修改界面代碼,打自己公司的廣告等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章