过滤、排序、异常处理
过滤
#1 安装:pip3 install django-filter
#2 注册,在app中注册
#3 全局配,或者局部配
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
#4 视图类
class BooksView(ListAPIView):
queryset = Books.objects.all()
serializer_class = BooksModelSerializer
# 过滤
filter_fields = ('book_name', 'publish') # 配置可以按照哪个字段来过滤,可以是多个
# http://127.0.0.1:8000/api/day05/book/?book_name=西游记
# http://127.0.0.1:8000/api/day05/book/?publish=1
# http://127.0.0.1:8000/api/day05/book/?book_name=西游记&publish=1
排序
from rest_framework.filters import OrderingFilter
# 排序
class BooksView2(ListAPIView):
queryset = Books.objects.all()
serializer_class = BooksModelSerializer
filter_backends = [OrderingFilter]
ordering_fields = ('id', 'price')
# urls.py
path('books2/', views.Book2View.as_view()),
http://127.0.0.1:8000/api/day05/book2/?ordering=-price,id # 降序
http://127.0.0.1:8000/api/day05/book2/?ordering=price,id # 升序
如果需要在过滤以后再次进行排序,则需要两者结合!
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
# 排序
class BooksView2(ListAPIView):
queryset = Books.objects.all()
serializer_class = BooksModelSerializer
# 因为局部配置会覆盖全局配置,所以需要重新把过滤组件核心类再次声明,
# 否则过滤功能会失效
filter_backends = [OrderingFilter, DjangoFilterBackend]
ordering_fields = ('id', 'price')
# urls.py
path('books2/', views.Book2View.as_view()),
http://127.0.0.1:8000/api/day05/book2/?ordering=-price # 降序
http://127.0.0.1:8000/api/day05/book2/?ordering=price # 升序
分页
- 只有查所有才需要分页
drf内置了三种分页方式
1、PageNumberPagination
"""
PageNumberPagination
page_size:每页展示得条数
page_query_param:每页得前缀参数,默认是page
page_size_query_param:可以在url中控制展示多少条数据
max_page_size:每页最大显示条数
"""
from rest_framework.pagination import PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 3 # 每页条数
# http://127.0.0.1:8000/api/books2/?aaa=1
page_query_param = 'page' # 指定每页得前缀参数,默认是page
page_size_query_param = 'size' # 每一页显示的条数
max_page_size = 5 # 每页最大显示条数
class BookListAPIView(ListAPIView):
queryset = models.Book.objects.all().filter(is_delete=False)
serializer_class = ser.BookModelSerializer
# 配置分页
# pagination_class = PageNumberPagination # 内置(无法修改四个属性)
pagination_class = MyPageNumberPagination # 自定制
# 继承APIView
class Mypage(PageNumberPagination):
page_size = 2
page_query_param = 'page'
# 定制传参
page_size_query_param = 'size'
# 最大一页的数据
max_page_size = 5
class Pager(APIView):
def get(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)
配置文件中指定PAGE_SIZE
REST_FRAMEWORK = {
'PAGE_SIZE': 2,
}
2、LimitOffsetPagination
"""
LimitOffsetPagination
default_limit = 1 默认展示条数
limit_query_param = 'limit' url修改展示条数的前缀词
# http://127.0.0.1:8000/api/books2/?limit=1&offset=1,此处页面展示一条数据,该数据pk为2
offset_query_param = 'offset' 标杆位置的前缀词,标杆是几就从标杆的后一位开始展示
max_limit = None 最大显示条数
"""
from rest_framework.pagination import LimitOffsetPagination
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 1 # 默认展示条数
limit_query_param = 'limit' # url修改展示条数的前缀词
offset_query_param = 'offset' # 标杆位置的前缀词,标杆是几就从标杆的后一位开始展示
max_limit = 5 # 最大显示条数
class BookListAPIView(ListAPIView):
queryset = models.Book.objects.all()
serializer_class = ser.BookModelSerializer
# 配置分页
pagination_class = MyLimitOffsetPagination
# 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
"""
CursorPagination
cursor_query_param = 'cursor' # 每页得前缀参数,默认是cursor
page_size = 2 # 每页显示条数
ordering = 'id' # 排序字段,字段不存在则报错,默认升序,降序:-字段名
"""
from rest_framework.pagination import CursorPagination
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 每页得前缀参数,默认是cursor
page_size = 2 # 每页显示条数
ordering = 'id' # 排序字段,字段不存在则报错
class BookListAPIView(ListAPIView):
queryset = models.Book.objects.all()
serializer_class = ser.BookModelSerializer
# 配置分页
pagination_class = MyCursorPagination
# APIView
# 看源码,是通过sql查询,大于id和小于id
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)
异常处理(需要统一接口返回)
# 自定义异常方法,替换掉全局
# 写一个方法
# 自定义异常处理的方法
from rest_framework.views import exception_handler
from rest_framework.response import Response
from rest_framework import status
def my_exception_handler(exc, context):
response = exception_handler(exc, context)
# response两种情况,一种是None,drf没有处理,交给django处理,直接返回了异常页面
# 另一种是response对象,django处理了但是不符合要求
# 我们需要统一要求,但凡抛异常都让它以json格式返回
print(type(exc))
if not response:
if isinstance(exc, ZeroDivisionError):
return APIResponse(code=777, message='1/0错误', status=status.HTTP_400_BAD_REQUEST)
return APIResponse(code=999, message=str(exc), status=status.HTTP_400_BAD_REQUEST)
else:
return APIResponse(code=888, message=response.data.get('detail'), status=status.HTTP_400_BAD_REQUEST)
# 全局配置setting.py
'EXCEPTION_HANDLER': 'xxx.user_auth.my_exception_handler',
class TestView2(APIView):
authentication_classes = []
permission_classes = []
def get(self, request):
1/0
return APIResponse(message='游客访问')
封装Response方法
from rest_framework.response import Response
from rest_framework.status import HTTP_200_OK
class APIResponse(Response):
def __init__(self, code=100, message='成功', result=None, status=HTTP_200_OK, headers=None, **kwargs):
back_dic = {
'code': code,
'message': message
}
back_dic.update(kwargs)
if result:
back_dic['result'] = result
super().__init__(data=back_dic, status=status, headers=headers)