DRF-通用分頁器(PageNumberPagination):ListModelMixin可以使用的通用分頁器

一、ListModelMixin 和GenericAPIView源碼

ListModelMixin 是一個單一功能類,必須配合GenericAPIView(或其子類)來一起使用,才能完成其視圖的功能

class ListModelMixin:"""List a queryset."""def list(self, request, *args, **kwargs):#1、這里獲取querysetqueryset = self.filter_queryset(self.get_queryset())#2、這里獲取當前頁的queryset數據,[<數據模型>]page = self.paginate_queryset(queryset)if page is not None:#3、對當前頁的模型對象,進行序列化serializer = self.get_serializer(page, many=True)#4、獲取到當前頁的數據,里面整合了當前頁的序列化數據return self.get_paginated_response(serializer.data)serializer = self.get_serializer(queryset, many=True)return Response(serializer.data)

主要就按照:一步一步走就可以了,如果ListModelMixin沒有的方法,就去GenericAPIView找

self.filter_queryset(self.get_queryset())--->self.paginate_queryset(queryset)-->self.get_serializer(page, many=True)-->self.get_paginated_response(serializer.data)

1、ListModelMixin : queryset = self.filter_queryset(self.get_queryset())

當前類是沒有實現get_queryset和filter_queryset方法的,

配合GenericAPIView使用,調用的是GenericAPIView的get_queryset和filter_queryset方法

2、GenericAPIView:? get_queryset, 拿到queryset對象

    def get_queryset(self):queryset = self.querysetif isinstance(queryset, QuerySet):queryset = queryset.all()return queryset

3、GenericAPIView:filter_queryset 這個是過濾器,沒有配置就是空,沒有做如何操作

4、GenericAPIView:paginate_queryset(queryset) :

4.1、GenericPAIView : paginator : 拿到配置的分頁器類,返回分頁器的實例化對象

@property
def paginator(self):if not hasattr(self, '_paginator'):if self.pagination_class is None:self._paginator = Noneelse:self._paginator = self.pagination_class()return self._paginator

4.2、根據4.1,拿到的分頁器對象,調用分頁器的paginate_queryset 方法: 該方法就是返回當前頁的queryset

 def paginate_queryset(self, queryset):if self.paginator is None:return Nonereturn self.paginator.paginate_queryset(queryset, self.request, view=self)

5、GenericAPIView: get_paginated_response 方法: 調用分頁器對象的get_paginated_response

def get_paginated_response(self, data):assert self.paginator is not Nonereturn self.paginator.get_paginated_response(data)

總結來說:

1、要滿足第一個要求,符合ListModelMixin的功能,需要在自定義的分頁器類中重寫paginate_queryset和get_paginated_response

2、在start方法中,調用這兩個方法

3、再開一個方法handle_data,在get_paginated_response中調用這個方法,后續重寫handle_data來進行數據定制功能

二、自定義PageNumber的分頁器

(1)自定義的基本分頁器類

from rest_framework.pagination import PageNumberPaginationclass GenericPageNumberPagination(PageNumberPagination):page_size = 20page_query_param = 'page'page_size_query_param = 'page_size'max_page_size = page_size+(page_size//2)#重寫父類的: 校驗page_sizedef get_page_size(self, request):'''功能:校驗page_size,沒有傳遞或傳遞類型有問題時,按照默認的大小設置,超過最大頁面大小時,設置成最大頁面:param request::return: 數值'''page_size = request.GET.get(self.page_size_query_param)if not page_size:page_size = self.page_size #取的是類的page_sizeelse:try:page_size = int(page_size)except Exception:page_size = self.page_size #取的是類的page_sizeif page_size > self.max_page_size:page_size = self.max_page_size#給分頁的實例對象賦值每頁大小self.page_size = page_sizereturn self.page_size#自己定義: 校驗pagedef get_page(self,request,queryset,page_size):'''功能:判斷攜帶page是否合法,頁碼必須大于0,不能大于最大頁數,頁碼必須是數值:param request: 當前請求對象:param queryset: 模型uqeryset:param page_size:  每頁大小:return: None,{"error":'錯誤消息'},數值'''page = request.GET.get(self.page_query_param)if page == None:return Nonetry:page = int(page)self.page = page#判斷查詢的頁碼是否大于0if page <=0:self.page = {'error':'頁碼必須大于0','code':400}#總數據量self.count = len(queryset)##判斷查詢的數據是否有數據if self.count == 0:self.page = {'error':'查詢不到相關數據','code':400}#總頁數self.pages, has_number = divmod(self.count,page_size)if has_number:self.pages += 1## 判斷查詢的頁碼是否大于總頁碼if page > self.pages:self.page = {'error':f'查詢的頁碼{page}大于總頁碼數{self.pages}','code':400}return self.pageexcept Exception:self.page = {'error':'頁碼必須是數值','code':400}return self.page#自定義的def has_next_page(self,page=None,pages = None):'''是否有下一頁的數據:param page: 當前頁:param pages: 總頁數:return: 0或1'''if page == None:page = self.pageif pages == None:pages = self.pagesif page == 1:if pages <= 1:return 0else:return 1else:#page > 1if pages > page:return 1else:return 0#自定義的def has_previous_page(self,page=None,pages = None):'''功能:是否有上一頁的數據:param page: 當前頁:param pages: 總頁數:return: 0或1'''if page == None:page = self.pageif pages == None:pages = self.pagesif pages <=1:return 0else:if page>1:return 1else:return 0#重寫父類的: 獲取當前頁的QuerySet對象def paginate_queryset(self, queryset, request, view=None):'''功能:獲取當前頁的queryset對象:param queryset: 所有的queryset:param request: 當前請求:param view: 當前視圖類:return: None,{’error‘:''}, QuerySet'''page_size = self.get_page_size(request)page = self.get_page(request,queryset,page_size)if isinstance(page,dict) or page == None:#page參數錯誤,沒有傳遞page時return pagequeryset_len = len(queryset)if queryset_len == 0:return {'error':'查詢不到相關數據','code':400}#1、總數據量,在get_page 中就設置了self.count = len(queryset)#2、總頁數,在get_page 中就設置了self.pages, has_number = divmod(self.count, page_size)if has_number:self.pages += 1# 3、下一頁self.next = self.has_next_page()  # 有下一頁,返回1,沒有返回0# 4、上一頁self.previous = self.has_next_page()  # 有上一頁時,返回1,沒有返回0#5、當前頁self.current_page = self.page#6、截取指定的數據if self.page == 1:self.queryset = queryset[:self.page_size]else:start = self.page_size*(self.page-1)end = self.page_size*(self.page)self.queryset = queryset[start:end]return self.queryset#重寫父類的:將當前頁的QuerySet對象序列化def get_paginated_response(self,page_queryset,serializer_class=None):'''功能:根據傳遞進來的dict,None(page沒有傳遞,就不返回數據了),當前頁的List,當前頁QuerySet,:param page_queryset: dict,None,List,QuerySet:param serializer_class: 序列化器類:return: {}'''if isinstance(page_queryset,dict):#paginate_queryset的錯誤消息return page_querysetelif isinstance(page_queryset,list):data = {'code': 201,'msg': '獲取數據成功','data': '',  # 當前頁數據'next': self.has_next_page(),  # 是否有下一頁'previous': self.has_previous_page(),  # 是否有上一頁'count': self.count,  # 總數據量'pages': self.pages,  # 總頁碼數'current_page': self.page,  # 當前頁碼'page_size': self.page_size,  # 每頁大小}if serializer_class:#1、手動使用start方法調用時,page_ser = serializer_class(instance=page_queryset, many=True)page_data = page_ser.datadata['data'] = page_datareturn dataelse:#2、配合mixins.ListModelMixin源碼使用, 其調用了paginate_queryset,拿到queryset對象,將序列化結果傳遞進來page_queryset = self.handle_data(page_queryset)data['data'] = page_querysetreturn dataelif page_queryset == None:return {'code':400,'error':'沒有傳遞頁碼值'}else:raise Exception('分頁器只支持,dict,list,QuerySet,None 類型')#自己定義的,對當前頁數據,進一步的處理def handle_data(self,data_list):return data_list#手動調用時,獲取結果的def start(self,request,serializer_class,queryset):#1、獲取當前頁的QuerySet對象page_queryset = self.paginate_queryset(queryset=queryset,request=request)if page_queryset == None:return {'code':400,'error':'頁碼必須攜帶'}if isinstance(page_queryset,dict):return page_queryset#2、將當前頁的QuerySet對象傳遞進去,得到分頁的響應結果page_data = self.get_paginated_response(page_queryset=page_queryset,serializer_class=serializer_class)return page_dataif __name__ == '__main__':'''mixins.ListModelMixin的調用邏輯:1、調用paginate_queryset2、1的返回值如果是None時,就不執行獲取分頁的數據,就去獲取所有的數據返回3、1的返回值不為None時,就執行get_paginated_response,拿到分頁的結果手動調用使用:data = page.start(request,序列化類,模型對象)'''

(2)、使用

1、對于ListModelMixin,使用的邏輯是一樣的,無需變化。

2、手動使用

page = GenericPageNumberPagination()
page_data = page.start(request,'序列化器類','數據庫查詢的queryset')

(3)、繼承

對于需要特殊處理返回的數據時,可以繼承分頁器類,重寫handle_data方法

class UserPageNumberPagination(GenericPageNumberPagination):def handle_data(self,data_list):for dic in data_list:dic['type'] = '患者'return data_list#使用
page = UserPageNumberPagination()
page_data = page.start(request,'序列化器類','數據庫查詢到關于用戶的queryset')

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165264.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165264.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165264.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

騰訊云點播小程序端上傳 SDK

云點播是專門應對上傳大視頻文件的。 騰訊云點播文檔&#xff1a;https://cloud.tencent.com/document/product/266/18177 這個文檔比較簡單&#xff0c;實在不行&#xff0c;把demo下載下來&#xff0c;一看就明白了&#xff0c;然后再揉一下挪到自己的項目里。完事。 getSign…

芯知識 | 混音播報語音芯片的優勢:革新音頻應用的新力量

隨著科技的進步&#xff0c;語音芯片在各個領域的應用越來越廣泛。而在眾多語音芯片中&#xff0c;混音播報語音芯片以其獨特的優勢&#xff0c;正逐漸成為音頻應用領域的翹楚。本文將重點探討混音播報語音芯片的優勢及其在現代科技應用中的價值。 一、混音播報語音芯片概述 …

element-vue實現網頁鎖屏功能

1.寫一個鎖屏頁面&#xff0c;這里比較簡單&#xff0c;自己定義一下,需要放到底層HTML中哦&#xff0c;比如index.html <div id"appIndex"><el-dialog title"請輸入密碼解鎖屏幕" :visible.sync"lockScreenFlag" :close-on-click-mod…

力扣236. 二叉樹的最近公共祖先(java DFS解法)

Problem: 236. 二叉樹的最近公共祖先 文章目錄 題目描述思路解題方法復雜度Code 題目描述 給定一個二叉樹, 找到該樹中兩個指定節點的最近公共祖先。 百度百科中最近公共祖先的定義為&#xff1a;“對于有根樹 T 的兩個節點 p、q&#xff0c;最近公共祖先表示為一個節點 x&am…

Android逆向一-frida操作

系列文章目錄 第一章 frida操作 文章目錄 系列文章目錄前言一、兩種模式二、frida命令行執行及參數三、frida使用python執行四、動靜態域調用1. 靜態域調用2.動態域調用 五. 遠程rpc調用六. 補充總結 前言 熟悉frida操作&#xff0c;hook手機app的關鍵位置進行逆向操作 一、…

芯知識 | Flash可更換聲音語音芯片—引領音頻IC技術革新的新篇章

隨著科技的飛速發展&#xff0c;人們對于電子產品的音頻性能要求越來越高。在這種背景下&#xff0c;Flash可更換聲音語音芯片應運而生&#xff0c;成為音頻技術領域的一顆璀璨明星。本文將詳細介紹Flash可更換聲音語音芯片的特點、優勢以及應用場景&#xff0c;展望其在未來科…

【Docker】從零開始:10.registry搭建私有倉庫

【Docker】從零開始&#xff1a;10.registry搭建私有倉庫 為什么要使用私有倉庫關于Docker Registry基于容器搭建registry私有倉庫1.下載鏡像2. 啟動鏡像3.修改系統配置文件4.下載ubuntu鏡像&#xff0c;修改名稱3.提交鏡像4.查看鏡像 本地搭建私有倉庫(目前編譯報錯找不到包&a…

【管理運籌學】背誦手冊(五)| 動態規劃

五、動態規劃 基本概念 階段&#xff08;Stage&#xff09;&#xff1a;將所給問題的過程&#xff0c;按時間或空間特征分解成若干相互聯系的階段&#xff0c;以便按次序去求解每階段的解&#xff0c;常用字母 k k k 表示。 狀態&#xff08;State&#xff09;&#xff1a;…

java實現連接linux(上傳文件,執行shell命令等)

1 導入pom <dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version></dependency> 2 編寫配置類 package com.budwk.app.atest;import com.budwk.app.common.config.AppExceptio…

計算機網絡之網絡層

一、概述 主要任務是實現網絡互連&#xff0c;進而實現數據包在各網絡之間的傳輸 1.1網絡引入的目的 從7層結構上看&#xff0c;網絡層下是數據鏈路層 從4層結構上看&#xff0c;網絡層下面是網絡接口層 至少我們看到的網絡層下面是以太網 以太網解決了什么問題&#xff1f; 答…

【Python 千題 —— 基礎篇】刪除列表值

題目描述 題目描述 刪除列表的指定值。有一個列表 [1, 3, 5, 2, 44, 1, 9, 10, 32] &#xff0c;請使用 for 循環刪除該列表中與 [44, 1, 9] 列表相同的值&#xff0c;并輸出該列表。 輸入描述 無輸入。 輸出描述 輸出操作后的列表。 示例 示例 ① 輸出&#xff1a; …

記錄:通過day.js獲取兩個日期相差的時間,并轉化為年月日的格式

day.js這個日期庫真的是很不錯的日期庫&#xff0c;足夠滿足日常的開發需求。 Day.js中文網 (fenxianglu.cn) 需求&#xff1a;獲取兩個日期相差的時間&#xff0c;轉化為年月日的形式&#xff1b;話不多少&#xff0c;直接放代碼 import dayjs from "dayjs"; imp…

計算機網絡之應用層

一、概述 引入目的&#xff1a; 為了方便用戶去使用&#xff1b; 該如何方便用戶使用網絡呢&#xff0c;即怎樣幫助用戶使用網絡&#xff1f; 1.用戶需要知道網絡資源所在的位置 2.網絡上資源一定是在資源子網的主機上 3.資源子網上的主機&#xff0c;在通信子網中用IP地…

qt-C++筆記之終端Ctrl+C關閉界面和ROS節點

qt-C筆記之終端CtrlC關閉界面和ROS節點 code review! 文章目錄 qt-C筆記之終端CtrlC關閉界面和ROS節點1.運行2.main.cpp3.main_window.hpp 1.運行 2.main.cpp 3.main_window.hpp

vue-router 路由權限,路由導航守衛

addRouter() 添加路由 使用場景 列如&#xff1a;菜單權限的分配&#xff08;管理員與用戶不一致&#xff09; 根據后臺返回 參數 定義isAdmin根據isAdmin 分配 let isAdmin true // 添加路由 可以傳參 一級路由名稱 來添加二級路由 if (isAdmin) {router.addRoute({path: /…

SpringCloud 微服務全棧體系(十六)

第十一章 分布式搜索引擎 elasticsearch 六、DSL 查詢文檔 elasticsearch 的查詢依然是基于 JSON 風格的 DSL 來實現的。 1. DSL 查詢分類 Elasticsearch 提供了基于 JSON 的 DSL&#xff08;Domain Specific Language&#xff09;來定義查詢。常見的查詢類型包括&#xff1…

P1030 [NOIP2001 普及組] 求先序排列

1.先找根&#xff08;后序最后一個元素&#xff09; 2.以根分中序為兩個中序即&#xff1a; (相當于分為兩個子樹) A中序 對應->A后序 &#xff08;長度對應&#xff09; B中序 對應->B后序 &#xff08;長度對應&#xff09; 遞歸循壞即可&#xff08;中序長度小…

【數據結構(C語言)】淺談棧和隊列

目錄 文章目錄 前言 一、棧 1.1 棧的概念及結構 1.2 棧的實現 1.2.1. 支持動態增長的棧的結構 1.2.2 初始化棧 1.2.3 入棧 1.2.4 出棧 1.2.5 獲取棧頂元素 1.2.6 獲取棧中有效元素個數 1.2.7 檢查棧是否為空 1.2.8 銷毀棧 二、隊列 2.1 隊列的概念及結構 2.2 隊…

Javaweb之前后臺分離開發介紹的詳細解析

2.1 前后臺分離開發介紹 在之前的課程中&#xff0c;我們介紹過&#xff0c;前端開發有2種方式&#xff1a;前后臺混合開發和前后臺分離開發。 前后臺混合開發&#xff0c;顧名思義就是前臺后臺代碼混在一起開發&#xff0c;如下圖所示&#xff1a; 這種開發模式有如下缺點&a…

守護進程的理解

什么是守護進程 daemon False # 是否以守護進程方式運行&#xff0c;True守護&#xff0c;False 非守護 在這段代碼中&#xff0c;daemon 變量的值決定了進程是否以守護進程方式運行。如果 daemon 的值為 True&#xff0c;則表示進程將以守護進程方式運行&#xff0c;否則為…