-drf-過濾排序分頁異常處理
一 過濾Filtering
1 內建過濾
# 模組匯入
from rest_framework.filters import SearchFilter
1.過濾目的:篩選查詢結果(模糊匹配,只要含有就匹配出來) 2.內建篩選使用 -在檢視類中配置 filter_backends =[SearchFilter,] # 匹配所有欄位進行過濾篩選 -http://127.0.0.1:8000/books/?search=i # 只要有一個物件中的不論任何欄位模糊匹配到i,就過濾出來 filter_backends = [SearchFilter, ] search_fields = ('title',) # 匹配title欄位進行過濾篩選 -http://127.0.0.1:8000/books/?search=i # 這樣是隻要有一個物件中的title欄位模糊匹配到i,就過濾出來
2 第三方擴充套件的過濾功能
對於列表資料可能要根據欄位進行過濾,我們可以通過新增django-filter擴充套件來增強支援
# 安裝
pip install django-filter :最新版本(2.4.0)要跟django2.2以上搭配
在配置檔案中增加過濾後端的設定:
INSTALLED_APPS = [ ... 'django_filters', # 需要註冊應用, ] REST_FRAMEWORK = { ... 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) }
在檢視中新增filter_fields屬性,指定可以過濾的欄位
# 匯入模組
from django_filters.rest_framework import DjangoFilterBackend
class BookInfo(ModelViewSet): queryset = models.Book.objects.all() serializer_class = serializer.BookModelSerializer filter_backends = [DjangoFilterBackend, ] filter_fields = ('title', 'price') # 與內建的search方法不同 # 輸入的url -http://127.0.0.1:8000/books/?title=i 或 http://127.0.0.1:8000/books/?price=1 # 見名知意:可以直接在?欄位=匹配內容 的方式在book表中指定的該欄位模糊匹配過濾出資料物件
二 排序
對於列表資料,REST framework提供了OrderingFilter過濾器來幫助我們快速指明資料按照指定欄位進行排序。
使用方法:
在類檢視中設定filter_backends,使用rest_framework.filters.OrderingFilter
過濾器,REST framework會在請求的查詢字串引數中檢查是否包含了ordering引數,如果包含了ordering引數,則按照ordering引數指明的排序欄位對資料集進行排序。
前端可以傳遞的ordering引數的可選欄位值需要在ordering_fields中指明。
舉例:
# 匯入模組
from rest_framework.filters import OrderingFilter
class BookInfo(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
filter_backends = [OrderingFilter, ]
ordering_fields = ('price',) # 指定欄位,預設升序排序
-http://127.0.0.1:8000/books/?ordering=price # 也需要在url配置相應的引數
# ordering_fields = ('-price',) # 降序排序
如果需要在過濾以後再次進行排序,則需要兩者結合
class BookInfo(ModelViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
throttle_classes = [AnonRateThrottle, UserRateThrottle]
filter_backends = [DjangoFilterBackend, OrderingFilter]
filter_fields = ('publish',)
ordering_fields = ('price',)
-http://127.0.0.1:8000/books/?publish=1&ordering=price
# 在過濾出出版社publish=1後,將過濾物件以Price升序排序
三 分頁Pagination
REST framework提供了分頁的支援。
我們可以在配置檔案中設定全域性的分頁方式,如:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 100 # 每頁數目
}
注意:如果在檢視內關閉分頁功能,只需在檢視內設定
pagination_class = None
也可以通過自定義Pagination類,來為檢視新增不同分頁行為。在檢視中通過pagination_clas
屬性來指明。
# 匯入模組
from rest_framework.pagination import PageNumberPagination
from rest_framework.generics import ListAPIView
# myauth.py
class ResultSetPagination(PageNumberPagination):
page_size = 2 # 每頁顯示的條數
page_query_param = 'page' # 前端返回來查詢頁數的關鍵字
max_page_size = 30 # 前端顯示的最多的頁數
# views.py
# path('books/', views.BookInfo.as_view({"get": "list"}))
class BookInfo(ListModelMixin, GenericViewSet): # 只進行查詢所有資料的介面不用寫get方法
# 路由已經進行了配置
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = myauth.ResultSetPagination
1 PageNumberPagination:普通分頁
前端訪問網址形式:
GET http://127.0.0.1:8000/books/?page=3&size=1
找到第三頁從上到下數的第一條資料
可以在子類中定義的屬性:
- page_szie 每頁的條數,後端預設的,如果前端有指定按照前端指定的
- page_query_param 前端傳送頁數的關鍵字名,預設為“page”
- page_size_query_param 前端傳送的每頁條數的關鍵字名,預設為None
- max_page_size 前端最多能設定的分頁的總數
from rest_framework.pagination import PageNumberPagination
class ResultSetPagination(PageNumberPagination):
page_size = 2 # 每頁顯示的條數
page_query_param = 'page' # 前端返回來查詢頁數的關鍵字
max_page_size = 30 # 前端顯示的最多的頁數
page_size_query_param = 'size' # 前端傳送的每頁條數的關鍵字名
# views.py
class BookInfo(ListModelMixin, GenericViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = myauth.ResultSetPagination
APIView的分頁模式
-新建一個類,繼承普通分頁,重寫四個屬性
-檢視類寫法如下
class StudentApiView(APIView):
def get(self,request):
student_list=Student.objects.all()
page=MyPageNumberPagination()# 例項化得到物件
# 只需要換不同的分頁類即可
res=page.paginate_queryset(student_list,request,self)# 開始分頁
ser=StudentSerializer(res,many=True)
return page.get_paginated_response(ser.data) # 返回資料
2 LimitOffsetPagination:偏移分頁
前端訪問網址形式:
GET http://127.0.0.1/books/?limit=2&offset=4
找到第四條資料然後以兩條資料為一頁進行分頁(起始資料從5開始不包含4)
可以在子類中定義的屬性:
- deault_limit 每頁條數,後端預設的,如果前端有指定按照前端指定的
- limit_query_param 前端指定每頁查詢多少條的關鍵字
- offset_query_param 前端指定查詢的起始位置的關鍵字
- max_limit 查詢時最多返回多少條
from rest_framework.pagination import LimitOffsetPagination
# auth.py
class LimitSetPagination(LimitOffsetPagination):
default_limit = 3
limit_query_param = 'limit'
offset_query_param = 'offset'
# views.py
class BookInfo(ListModelMixin, GenericViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = myauth.LimitSetPagination
APIView的分頁模式
class Pager(APIView):
def get(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)
3 CursorPagination:遊標分頁
速度快:檢索資料方式,是在當前頁面向上或向下檢索
GET http://127.0.0.1:8000/books/?cursor=bz0z&page=3
# cursor遊標標識跳轉的當前頁面,遊標卡在當前頁面的上下,所以查詢速度很快,直接在當前遊標向上或向下檢索。但是也限制了不能直接跳轉到其他頁面只能上下。
可以在子類中定義的屬性:
- cursor_query_param: 預設查詢欄位,不需要修改,前端指定查詢的關鍵字
- page_size:每頁數目,後端預設的,如果前端有指定按照前端指定的
- ordering:按什麼排序,需要指定
- page_size_query_param 前端傳送的每頁條數的關鍵字名,預設為None
from rest_framework.pagination import CursorPagination
# auth.py
class CursorSetPagination(CursorPagination):
page_size = 2 # 預設頁面條數
ordering = 'id'
cursor_query_param = 'cursor' # 預設cursor 可以不寫
page_size_query_param = 'page' # 前端指定頁面條數,則按前端指定的來
# views.py
class BookInfo(ListModelMixin, GenericViewSet):
queryset = models.Book.objects.all()
serializer_class = serializer.BookModelSerializer
pagination_class = myauth.CursorSetPagination
APIView分頁模式
class Pager(APIView):
def get(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)
四 異常處理Exceptions
REST framework提供了異常處理,我們可以自定義異常處理函式
1 使用方式
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
print(str(exc))
# 先呼叫drf預設的異常處理方式獲得標準錯誤響應物件
response = exception_handler(exc, context)
# 在此處補充自定的異常處理,返回前端
if response is None: # 沒有返回值代表有異常
response = Response({'detail': str(exc)})
return response
在配置檔案中宣告自定義的異常處理
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'app10.myauth.custom_exception_handler',
}
如果未宣告,會採用預設的方式,如下
rest_frame/settings.py
REST_FRAMEWORK = {
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
2 補充上處理關於資料庫的異常
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'
}
3 REST framework定義的異常
- APIException 所有異常的父類
- ParseError 解析錯誤
- AuthenticationFailed 認證失敗
- NotAuthenticated 尚未認證
- PermissionDenied 許可權決絕
- NotFound 未找到
- MethodNotAllowed 請求方式不支援
- NotAcceptable 要獲取的資料格式不支援
- Throttled 超過限流次數
- ValidationError 校驗失敗