1. 程式人生 > 實用技巧 >drf-過濾排序異常處理封裝Response物件

drf-過濾排序異常處理封裝Response物件

一 過濾Filtering

對於列表資料可能需要根據欄位進行過濾,我們可以通過新增django-fitlter擴充套件來增強支援。

安裝

pip install django-filter
註冊

INSTALLED_APPS = [
    ...
    'django_filters',  # 需要註冊應用,
]

全域性配置

REST_FRAMEWORK = {
    ...
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
}
# 在檢視中新增filter_fields屬性,指定可以過濾的欄位
class StudentListView(ListAPIView): queryset = Student.objects.all() serializer_class = StudentSerializer filter_fields = ('age', 'sex') # 127.0.0.1:8000/four/students/?sex=1

區域性配置

from django_filters.rest_framework import DjangoFilterBackend
class StudentListView(ListAPIView):
    ...
    filter_backends 
= [DjangoFilterBackend,] filter_fields = ('age', 'sex')

二 排序

對於列表資料,REST framework提供了OrderingFilter過濾器來幫助我們快速指明資料按照指定欄位進行排序。

使用方法:

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

前端可以傳遞的ordering引數的可選欄位值需要在ordering_fields中指明。

示例:

from rest_framework.generics import ListAPIView
from rest_framework.filters import OrderingFilter
from app01.models import Book
from app01.ser import BookSerializer
class Book2View(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [OrderingFilter]
    ordering_fields = ('id', 'price')

#使用 
http://127.0.0.1:8000/books2/?ordering=-price
http://127.0.0.1:8000/books2/?ordering=price
http://127.0.0.1:8000/books2/?ordering=-id
-id 表示針對id欄位進行倒序排序
id  表示針對id欄位進行升序排序

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

from django_filters.rest_framework import DjangoFilterBackend
class Book2View(ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_fields = ('id', 'price')  # 過濾
    # 因為區域性配置會覆蓋全域性配置,所以需要重新把過濾元件核心類再次宣告,
    # 否則過濾功能會失效
    filter_backends = [OrderingFilter,DjangoFilterBackend] # 過濾要寫在排序之後
    ordering_fields = ('id', 'prcie') #排序

三 異常處理 Exceptions

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

3.1 使用方式

from rest_framework.views import exception_handler

def my_exception_handler(exc, context):
    # 先呼叫REST framework預設的異常處理方法獲得標準錯誤響應物件
    response = exception_handler(exc, context)

    # 在此處補充自定義的異常處理
    if not response:
        if isinstance(exc, ZeroDivisionError):
            return Response(data={'status': 777, 'msg': "除以0的錯誤" + str(exc)}, status=status.HTTP_400_BAD_REQUEST)
        return Response(data={'status':999,'msg':str(exc)},status=status.HTTP_400_BAD_REQUEST)
    else:
        return Response(data={'status':888,'msg':response.data.get('detail')},status=status.HTTP_400_BAD_REQUEST)

在配置檔案中宣告自定義的異常處理

REST_FRAMEWORK = {
   'EXCEPTION_HANDLER': 'app01.app_auth.my_exception_handler',
}

3.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.3 REST framework定義的異常

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

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

四 封裝Response物件(重要)

為了讓放回的資料有一定的格式我們要使用自己封裝的Response物件

from rest_framework.response import Response
class APIResponse(Response):
    def __init__(self,code=100,msg='成功',data=None,status=None,headers=None,**kwargs):
        dic = {'code': code, 'msg': msg}
        if  data:
            dic = {'code': code, 'msg': msg,'data':data}
        dic.update(kwargs)
        super().__init__(data=dic, status=status,headers=headers)
# 使用
return APIResponse(data={"name":'lqz'},token='dsafsdfa',aa='dsafdsafasfdee')
return APIResponse(data={"name":'lqz'})
return APIResponse(code='101',msg='錯誤',data={"name":'lqz'},token='dsafsdfa',aa='dsafdsafasfdee',header={})