我們通常在使用Django爲前端或者用戶提供接口的時候,時常會遇到返回大量數據信息的情況,比如:有1000條用戶信息,有1000條新聞文章,有1000條商品信息等等。但是我們不可能將所有數據從數據庫獲取後一股腦的全部返回,這樣相當不好,會增大服務器壓力,同時也會增加前端渲染壓力,也不方便前端或者用戶使用。
這種情況下,我們就需要用到分頁處理。顧名思義,就是將大量數據進行分頁,每頁只有少量數據,在用戶希望通過接口獲取數據時,只需要在url中加入指定的參數,就可以獲取指定頁的數據,使用相當方便。
在Django中,我們通常使用django-rest-framework這個插件進行分頁,它提供了三種分頁器:PageNumber分頁(普通分頁)、LimitOffset分頁(偏移分頁)、Cursor分頁(加密分頁),我們可以根據實際情況選擇合適的分頁器,下面來依次介紹這三種分頁器。
一、PageNumber分頁
class TestApi1(APIView):
"""PageNumber分頁"""
def get(self, request):
page = PageNumberPagination() # 創建普通分頁器對象
page.page_size = 3 # 設置每頁數據條數
articles = Articles.get_articles() # 獲取所有文章數據
ret_page = page.paginate_queryset(articles, request, self) # 用實例化的分頁器對所有數據進行分頁,並且返回當前頁的數據的列表
articles_serializer = ArticlesSerializers(ret_page, many=True) # 將當前頁數據序列化
data = {
'count': articles.count(), # 獲取數據總數
'previous': page.get_previous_link(), # 獲取上一頁鏈接,如果沒有則是None
'next': page.get_next_link(), # 獲取下一頁鏈接,如果沒有則是None
'results': articles_serializer.data, # 當前頁的序列化數據
}
return Response(data, status=200)
在調用接口時,需要添加page參數,表示獲取哪一頁,如果沒有使用該參數,默認獲取第一頁,如果傳入不存在的頁數,則會返回404。
我這裏的本地的api是:http://127.0.0.1:8000/api/v1/blog/test1,沒有加參數表示獲取第一頁
觀察數據,的確是我想要的格式,這樣就可以了。再加入page參數試試:
二、LimitOffset分頁
class TestApi2(APIView):
"""LimitOffset分頁"""
def get(self, request):
page = LimitOffsetPagination() # 創建偏移分頁器對象
page.page_size = 3 # 設置每頁數據默認條數,在api中可以通過limit參數修改
articles = Articles.get_articles() # 獲取所有文章數據
ret_page = page.paginate_queryset(articles, request, self) # 用實例化的分頁器對所有數據進行分頁,並且返回當前頁的數據的列表
articles_serializer = ArticlesSerializers(ret_page, many=True) # 將當前頁數據序列化
data = {
'count': articles.count(), # 獲取數據總數
'previous': page.get_previous_link(), # 獲取上一頁鏈接,如果沒有則是None
'next': page.get_next_link(), # 獲取下一頁鏈接,如果沒有則是None
'results': articles_serializer.data, # 當前頁的序列化數據
}
return Response(data, status=200)
調用接口時,需要傳入兩個參數:offset、limit,其中,offset表示偏移量,即若offset=0,則從第一條數據算起,若offset=6,則從第七條數據開始算起,limit表示往後偏移多少,如:offset=2&limit=5表示從第3條數據是算起之後的第5條。若不傳參數默認獲取第一頁。
三、Cursor分頁
Cursor分頁(加密分頁)和以上兩種分頁不太一樣,它不能通過自由的傳參來獲取指定的頁面,只能通過返回給你的上一頁下一頁的url來實現一頁一頁的跳轉。其中還需要注意,Cursor分頁默認會用created這個字段來排序,如果你的數據表中沒有該字段,則可以使用分頁器的ordering屬性來自定義排序字段。
class TestApi3(APIView):
"""Cursor分頁"""
def get(self, request):
page = CursorPagination() # 創建加密分頁器對象
page.ordering = '-id' # 設置排序字段,按照id降序排列
page.page_size = 3 # 設置每頁數據條數
articles = Articles.get_articles() # 獲取所有文章數據
ret_page = page.paginate_queryset(articles, request, self) # 用實例化的分頁器對所有數據進行分頁,並且返回當前頁的數據的列表
articles_serializer = ArticlesSerializers(ret_page, many=True) # 將當前頁數據序列化
data = {
'count': articles.count(), # 獲取數據總數
'previous': page.get_previous_link(), # 獲取上一頁鏈接,如果沒有則是None
'next': page.get_next_link(), # 獲取下一頁鏈接,如果沒有則是None
'results': articles_serializer.data, # 當前頁的序列化數據
}
return Response(data, status=200)
第一步只能獲取第一頁:
這時可以看到我們獲取到了加密後的下一頁的url,我們可以通過請求這個url來獲取下一頁的數據。
通過以上描述,我們可以看到,我們每一個視圖我們都需要去實例化一個分頁器,然後去修改分頁器的一些屬性值來達到我們希望看到的效果,另外爲了讓數據清洗明瞭,我們每一次都還要單獨去定義一個data,來聲明返回數據的格式,雖然也不是很繁瑣,但是如果太多的話也不太好。
在django-rest-framework中,使用通用視圖或視圖集時是能夠自動執行分頁的。我們需要在配置文件中進行設置。
實現PageNumber分頁(以通用視圖ListAPIView爲例)
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 3,
}
class TestApi4(ListAPIView):
"""PageNumber分頁"""
queryset = Articles.get_articles()
serializer_class = ArticlesSerializers
看,數據格式已經爲我們定義好了,相當方便。
實現LimitOffset分頁(以通用視圖ListAPIView爲例)
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 3,
}
class TestApi5(ListAPIView):
"""LimitOffset分頁"""
queryset = Articles.get_articles()
serializer_class = ArticlesSerializers
實現Cursor分頁(以通用視圖ListAPIView爲例)
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.CursorPagination',
'PAGE_SIZE': 3,
}
class TestApi6(ListAPIView):
"""Cursor分頁"""
queryset = Articles.get_articles()
serializer_class = ArticlesSerializers
pagination_class = CursorPagination
pagination_class.ordering = '-id'
以上就是django-rest-framework分頁功能的基本實現,一般都是夠用的,如果需要有一些個性化的配置等等,可以參考官方文檔。