drf之過濾分頁異常


一 過濾Filtering

對於列表數據可能需要根據字段進行過濾,我們可以通過添加django-fitlter擴展來增強支持。

1
pip install django-filter

在配置文件中增加過濾后端的設置:

1
2
3
4
5
6
7
8
9
INSTALLED_APPS = [
...
'django_filters', # 需要注冊應用,
]

REST_FRAMEWORK = {
...
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}

在視圖中添加filter_fields屬性,指定可以過濾的字段

1
2
3
4
5
6
classStudentListView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentSerializer
filter_fields = ('age', 'sex')

# 127.0.0.1:8000/four/students/?sex=1

二 排序

對於列表數據,REST framework提供了OrderingFilter過濾器來幫助我們快速指明數據按照指定字段進行排序。

使用方法:

在類視圖中設置filter_backends,使用rest_framework.filters.OrderingFilter過濾器,REST framework會在請求的查詢字符串參數中檢查是否包含了ordering參數,如果包含了ordering參數,則按照ordering參數指明的排序字段對數據集進行排序。

前端可以傳遞的ordering參數的可選字段值需要在ordering_fields中指明。

示例:

1
2
3
4
5
6
7
8
9
classStudentListView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
filter_backends = [OrderingFilter]
ordering_fields = ('id', 'age')

# 127.0.0.1:8000/books/?ordering=-age
# -id 表示針對id字段進行倒序排序
# id 表示針對id字段進行升序排序

如果需要在過濾以后再次進行排序,則需要兩者結合!

1
2
3
4
5
6
7
8
9
10
11
12
from rest_framework.generics import ListAPIView
from students.models import Student
from .serializers import StudentModelSerializer
from django_filters.rest_framework import DjangoFilterBackend
class Student3ListView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
filter_fields = ('age', 'sex')
# 因為局部配置會覆蓋全局配置,所以需要重新把過濾組件核心類再次聲明,
# 否則過濾功能會失效
filter_backends = [OrderingFilter,DjangoFilterBackend]
ordering_fields = ('id', 'age')

三 分頁Pagination

REST framework提供了分頁的支持。

我們可以在配置文件中設置全局的分頁方式,如:

1
2
3
4
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100 # 每頁數目
}

也可通過自定義Pagination類,來為視圖添加不同分頁行為。在視圖中通過pagination_clas屬性來指明。

1
2
3
4
5
6
7
8
classLargeResultsSetPagination(PageNumberPagination):
page_size = 1000
page_size_query_param = 'page_size'
max_page_size = 10000
class BookDetailView(RetrieveAPIView):
queryset = BookInfo.objects.all()
serializer_class = BookInfoSerializer
pagination_class = LargeResultsSetPagination

注意:如果在視圖內關閉分頁功能,只需在視圖內設置

1
pagination_class = None

可選分頁器

1) PageNumberPagination

前端訪問網址形式:

1
GET http://127.0.0.1:8000/students/?page=4

可以在子類中定義的屬性:

  • page_size 每頁數目
  • page_query_param 前端發送的頁數關鍵字名,默認為”page”
  • page_size_query_param 前端發送的每頁數目關鍵字名,默認為None
  • max_page_size 前端最多能設置的每頁數量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# APIView
from rest_framework.pagination import PageNumberPagination
# 一 基本使用:url=url=http://127.0.0.1:8000/pager/?page=2&size=3,size無效
classPager(APIView):
defget(self,request,*args,**kwargs):
# 獲取所有數據
ret=models.Book.objects.all()
# 創建分頁對象
page=PageNumberPagination()
# 在數據庫中獲取分頁的數據
page_list=page.paginate_queryset(ret,request,view=self)
# 對分頁進行序列化
ser=BookSerializer1(instance=page_list,many=True)
return Response(ser.data)
# 二 自定制 url=http://127.0.0.1:8000/pager/?page=2&size=3
# size=30,無效,最多5條
classMypage(PageNumberPagination):
page_size = 2
page_query_param = 'page'
# 定制傳參
page_size_query_param = 'size'
# 最大一頁的數據
max_page_size = 5
classPager(APIView):
defget(self,request,*args,**kwargs):
# 獲取所有數據
ret=models.Book.objects.all()
# 創建分頁對象
page=Mypage()
# 在數據庫中獲取分頁的數據
page_list=page.paginate_queryset(ret,request,view=self)
# 對分頁進行序列化
ser=BookSerializer1(instance=page_list,many=True)
# return Response(ser.data)
# 這個也是返回Response對象,但是比基本的多了上一頁,下一頁,和總數據條數(了解即可)
return page.get_paginated_response(ser.data)

#ListAPIView

# 聲明分頁的配置類
from rest_framework.pagination import PageNumberPagination
classStandardPageNumberPagination(PageNumberPagination):
# 默認每一頁顯示的數據量
page_size = 2
# 允許客戶端通過get參數來控制每一頁的數據量
page_size_query_param = "size"
max_page_size = 10
# 自定義頁碼的參數名
page_query_param = "p"

classStudentAPIView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
pagination_class = StandardPageNumberPagination

# 127.0.0.1/four/students/?p=1&size=5

2)LimitOffsetPagination

前端訪問網址形式:

1
GET http://127.0.0.1/four/students/?limit=100&offset=400

可以在子類中定義的屬性:

  • default_limit 默認限制,默認值與PAGE_SIZE設置一直
  • limit_query_param limit參數名,默認’limit’
  • offset_query_param offset參數名,默認’offset’
  • max_limit 最大limit限制,默認None
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# APIView
# http://127.0.0.1:8000/pager/?offset=4&limit=3
from rest_framework.pagination import LimitOffsetPagination
# 也可以自定制,同簡單分頁
classPager(APIView):
defget(self,request,*args,**kwargs):
# 獲取所有數據
ret=models.Book.objects.all()
# 創建分頁對象
page=LimitOffsetPagination()
# 在數據庫中獲取分頁的數據
page_list=page.paginate_queryset(ret,request,view=self)
# 對分頁進行序列化
ser=BookSerializer1(instance=page_list,many=True)
# return page.get_paginated_response(ser.data)
return Response(ser.data)
#ListAPIView
from rest_framework.pagination import LimitOffsetPagination
classStandardLimitOffsetPagination(LimitOffsetPagination):
# 默認每一頁查詢的數據量,類似上面的page_size
default_limit = 2
limit_query_param = "size"
offset_query_param = "start"

classStudentAPIView(ListAPIView):
queryset = Student.objects.all()
serializer_class = StudentModelSerializer
# 調用頁碼分頁類
# pagination_class = StandardPageNumberPagination
# 調用查詢偏移分頁類
pagination_class = StandardLimitOffsetPagination

3)CursorPagination

前端訪問網址形式:

1
GET http://127.0.0.1/four/students/?cursor=cD0xNQ%3D%3D

可以在子類中定義的屬性:

  • cursor_query_param:默認查詢字段,不需要修改
  • page_size:每頁數目
  • ordering:按什么排序,需要指定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#APIView
from rest_framework.pagination import CursorPagination
# 看源碼,是通過sql查詢,大於id和小於id
classPager(APIView):
defget(self,request,*args,**kwargs):
# 獲取所有數據
ret=models.Book.objects.all()
# 創建分頁對象
page=CursorPagination()
page.ordering='nid'
# 在數據庫中獲取分頁的數據
page_list=page.paginate_queryset(ret,request,view=self)
# 對分頁進行序列化
ser=BookSerializer1(instance=page_list,many=True)
# 可以避免頁碼被猜到
return page.get_paginated_response(ser.data)
# ListAPIView
classMyCursorPagination(CursorPagination):
page_size=2
ordering='-id'
from rest_framework.generics import ListAPIView
classAuthorListView(ListAPIView):
serializer_class = serializers.AuthorModelSerializer
queryset = models.Author.objects.filter(is_delete=False)
pagination_class =MyCursorPagination

應用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 2
page_query_param = 'page'
# 定制傳參
page_size_query_param = 'size'
# 最大一頁的數據
max_page_size = 5

classMyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2
# 最大一頁的數據
max_limit = 5
classMyCursorPagination(CursorPagination):
page_size=2
ordering='-id'
from rest_framework.generics import ListAPIView
classAuthorListView(ListAPIView):
serializer_class = serializers.AuthorModelSerializer
queryset = models.Author.objects.filter(is_delete=False)
pagination_class =MyCursorPagination

四 異常處理 Exceptions

REST framework提供了異常處理,我們可以自定義異常處理函數。

4.1 使用方式

1
2
3
4
5
6
7
8
9
10
11
from rest_framework.views import exception_handler

defcustom_exception_handler(exc, context):
# 先調用REST framework默認的異常處理方法獲得標准錯誤響應對象
response = exception_handler(exc, context)

# 在此處補充自定義的異常處理
if response isNone:
response.data['status_code'] = response.status_code

return response

在配置文件中聲明自定義的異常處理

1
2
3
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}

如果未聲明,會采用默認的方式,如下

rest_frame/settings.py

1
2
3
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}

4.2 案例

補充上處理關於數據庫的異常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status
from django.db import DatabaseError

def exception_handler(exc, context):
response = drf_exception_handler(exc, context)

if response is None:
view = context['view']
print('[%s]: %s' % (view, exc))
if isinstance(exc, DatabaseError):
response = Response({'detail': '服務器內部錯誤'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
else:
response = Response({'detail': '未知錯誤'}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

return response

# 在setting.py中配置
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'app01.ser.exception_handler'
}

4.3 REST framework定義的異常

  • APIException 所有異常的父類
  • ParseError 解析錯誤
  • AuthenticationFailed 認證失敗
  • NotAuthenticated 尚未認證
  • PermissionDenied 權限決絕
  • NotFound 未找到
  • MethodNotAllowed 請求方式不支持
  • NotAcceptable 要獲取的數據格式不支持
  • Throttled 超過限流次數
  • ValidationError 校驗失敗

也就是說,很多的沒有在上面列出來的異常,就需要我們在自定義異常中自己處理了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM