DRF过滤、排序、异常处理、自定义Response、分页

过滤

# pip安装
# settings.py注册
# 全局配置
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.backends.DjangoFilterBackend'],
}

class NewNewBooksView(ListAPIView):
    filter_fields = ('name',)
    queryset = Book.objects.all()
    serializer_class = NewBookModelSerializer

re_path('books/v5/', views.NewNewNewBooksView.as_view()),

# 在路由配置中无需正则分组即可从类似http://127.0.0.1:8000/books/v5/?name=《456》的URL中提取过滤条件

注意:继承APIView或者View的视图类是不受过滤影响的,继承了GenericAPIView类或者其子类的视图类才受过滤影响

局部过滤

# 一般情况下都是局部过滤,直接在视图类中配置即可
class NewNewNewBooksView(ListAPIView, CreateAPIView):
    authentication_classes = []
    throttle_classes = []

    filter_backends = [DjangoFilterBackend] # 配置过滤类
    filter_fields = ('name',) # 配置过滤字段
    queryset = Book.objects.all()
    serializer_class = NewBookModelSerializer

排序

# 全局使用
class NewNewNewBooksView(ListAPIView, CreateAPIView):
    authentication_classes = []
    throttle_classes = []

    filter_backends = [DjangoFilterBackend,OrderingFilter]
    filter_fields = ('id','price')
    queryset = Book.objects.all()
    serializer_class = NewBookModelSerializer

http://127.0.0.1:8000/books/v5/?ordering=-id
http://127.0.0.1:8000/books/v5/?ordering=price

异常处理

def app01_exception_handler(exc, context):
    response = exception_handler(exc, context)
    if not response:
        return Response(data={'status': 1, 'msg': str(exc)}, status=status.HTTP_400_BAD_REQUEST)
    else:
        return Response(data={'status': 2, 'msg': response.data.get('detail')}, status=status.HTTP_400_BAD_REQUEST)

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'app01.views.app01_exception_handler',
}

封装Response对象

class APIResponse(Response):
    def __init__(self, code=100, msg='成功', data=None, status=None, headers=None, content_type=None,**kwargs):
        dict = {'code': code, 'msg': msg}
        if data:
            dict = {'code': code, 'msg': msg, 'data': data}
        dict.update(kwargs)
        super().__init__(data=dict, status=None,headers=None,
                         exception=False, content_type=None)
book_ser = BookModelSerializer(instance=book,data=request.data,partial=True) # 部分修改

分页

三种分页方式

from rest_framework.pagination import PageNumberPagination,LimitOffsetPagination,CursorPagination

PageNumberPagination

from rest_framework.pagination import PageNumberPagination,
class BookView(ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    pagination_class = PageNumberPagination
REST_FRAMEWORK = {
    'PAGE_SIZE': 2,
}

# page_size 即'PAGE_SIZE'
# page_query_param 即URL中的页码key
# page_size_query_param 指定为'size'即可在URL中传入size参数控制索取条数
# max_page_size 硬性规定每页最大条数
# 可以通过如下继承改变参数值

LimitOffsetPagination

from rest_framework.pagination import LimitOffsetPagination
class MYLimitOffsetPagination(LimitOffsetPagination):
    default_limit = settings.REST_FRAMEWORK['PAGE_SIZE'] # 每页数据条数
    limit_query_param = 'limit' # 指定每页条数的key
    offset_query_param = 'offset' # 相对起始位置偏移量,offset=2则从第三条开始取
    max_limit = None # 每页最大条数
class BookView(ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    pagination_class = MYLimitOffsetPagination

CursorPagination

from rest_framework.pagination import CursorPagination
class MYLimitOffsetPagination(CursorPagination):
    cursor_query_param = 'cursor' # 过滤key
    page_size = 3 # 每页条数
    ordering = '-id' # 排序字段
class BookView(ListAPIView):
    queryset = models.Book.objects.all()
    serializer_class = BookModelSerializer
    pagination_class = MYLimitOffsetPagination

# 只有向前向后两个按钮,无法跳跃到某一页或者某一条数据,但是相比上面两种效率更高

使用APIView创建视图类时分页

class BooksAPIView(APIView):
    def get(self, request, *args, **kwargs):
        book_list = models.Book.objects.filter(is_delete=False)
        page_cursor = PageNumberPagination()
        book_list = page_cursor.paginate_queryset(book_list,request,view=self)
        book_list_ser = BookModelSerializer(book_list, many=True)
        return Response(data=book_list_ser.data)