drf08 过滤、排序、分页、异常
目录
一、过滤Filtering
对于列表数据可能需要根据字段进行过滤,我们可以通过添加django-fitlter扩展来增强支持。
1.安装
# 1.安装
pip install django-filter
# 2.在settings的app中注册
INSTALLED_APPS = [
'django_filters', # 需要注册应用,
]
2.全局配置
from rest_framework import settings
REST_FRAMEWORK = {
# filters - Generic view behavior
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'],
}
3.局部配置
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from app05_api.models import Book
from app05_api.ser import BookModelSerializer
# 过滤
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter
class BookModelViewSet(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
# 过滤 - 配置可以按照哪个字段来过滤
# http://127.0.0.1:8000/app_auth/books/?title=赵张三李四历险
# filter_backends = [DjangoFilterBackend]
filter_fields = ('id','title', 'price')
4.访问
http://127.0.0.1:8000/app_auth/books/?title=赵张三李四历险
二、排序 OrderingFilter
对于列表数据,REST framework提供了OrderingFilter过滤器来帮助我们快速指明数据按照指定字段进行排序。
使用方法:
在类视图中设置filter_backends
,使用rest_framework.filters.OrderingFilter
过滤器,REST framework会在请求的查询字符串参数中检查是否包含了ordering参数,如果包含了ordering参数,则按照ordering
参数指明的排序字段对数据集进行排序。
前端可以传递的ordering参数的可选字段值需要在ordering_fields中指明。
1. 全局配置
from rest_framework import settings
REST_FRAMEWORK = {
# 设置排序过滤
'DEFAULT_FILTER_BACKENDS': ['rest_framework.filters.OrderingFilter',],
}
2. 局部配置
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from app05_api.models import Book
from app05_api.ser import BookModelSerializer
# 过滤
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter
class BookModelViewSet(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
# 排序 http://127.0.0.1:8000/app_auth/books/?ordering=-id
filter_backends = [OrderingFilter]
ordering_fields = ('id', 'price')
# 必须是ordering=某个值
# -id 表示针对id字段进行倒序排序
# id 表示针对id字段进行升序排序
3. 访问
http://127.0.0.1:8000/app_auth/books/?ordering=-id
4.总结 - 过滤+排序
如果需要在过滤以后再次进行排序,则需要两者结合!
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from app05_api.models import Book
from app05_api.ser import BookModelSerializer
# 过滤
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter
class BookModelViewSet(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
# 过滤 - 配置可以按照哪个字段来过滤
filter_backends = [DjangoFilterBackend,OrderingFilter]
filter_fields = ('id','title', 'price')
ordering_fields = ('id', 'price')
# 访问
http://127.0.0.1:8000/app_auth/books/?price=3453.44&ordering=-id
三、分页
1.分页类型
1.1 PageNumberPagination -常用
前端访问网址形式:
# http://127.0.0.1:8000/api/books/?page=1&size=2
# 解释: page 当前页 size 展示条数
page_size
每页数目page_query_param
前端发送的页数关键字名,默认为"page"page_size_query_param
前端发送的每页数目关键字名,默认为Nonemax_page_size
前端最多能设置的每页数量
# http://127.0.0.1:8000/api/books/?page=1&size=2
# 解释: page 当前页 size 展示条数
class MyPageNumberPagination(PageNumberPagination):
page_size=3 #每页条数
page_query_param='page' #查询第几页的key - 参数可自己设置
page_size_query_param='size' # 每一页显示的条数 - 参数可自己设置
max_page_size=5 # 每页最大显示条数 - 多了不显示
1.2 LimitOffsetPagination
前端访问网址形式:
# http://127.0.0.1:8000/app_auth/books/?limit=2&offset=2
# 解释: offset 偏移量 limit 展示条数 - 用法同sql的分页类似
可以在子类中定义的属性:
default_limit
默认限制,每页数据量大小,默认值与PAGE_SIZE
设置一致limit_query_param
limit参数名,默认'limit' , 可以通过这个参数来改名字offset_query_param
offset参数名,默认'offset' ,可以通过这个参数来改名字max_limit
最大limit限制,默认None, 无限制
# http://127.0.0.1:8000/app_auth/books/?limit=2&offset=2
# 解释: offset 偏移量 limit 展示条数 - 用法同sql的分页类似
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3 # 每页条数
limit_query_param = 'limit' # 往后拿几条
offset_query_param = 'offset' # 标杆
max_limit = 5 # 每页最大几条
1.3 CursorPagination -速度最快
前端访问网址形式:
# http://127.0.0.1:8000/app_auth/books/?ordering=id
# 解释: 速度最快 只需要指定字段排序
可以在子类中定义的属性:
cursor_query_param
默认'cursor’,可以通过这个参数来改名字page_size
每页显示条数ordering
排序字段
# http://127.0.0.1:8000/app_auth/books/?ordering=id
# 解释: 速度最快 只需要指定字段排序
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 每一页查询的key
page_size = 2 #每页显示的条数
ordering = '-id' #排序字段
2.全局配置
from rest_framework import settings
REST_FRAMEWORK = {
# Pagination
# 设置每页大小
# 'DEFAULT_PAGINATION_CLASS':
# 'rest_framework.pagination.PageNumberPagination',
# 'rest_framework.pagination.LimitOffsetPagination',
# 'rest_framework.pagination.CursorPagination',
'PAGE_SIZE': 3,
}
3.局部配置
from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet
from app05_api.models import Book
from app05_api.ser import BookModelSerializer
# 过滤
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter
class BookModelViewSet(ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookModelSerializer
# 分页
pagination_class =PageNumberPagination
# pagination_class =LimitOffsetPagination
# pagination_class =CursorPagination
4.自定义分页 - 可选
from rest_framework.pagination import PageNumberPagination
class MyPageNumberPagination(PageNumberPagination):
page_size = 3 # 每页条数
page_query_param = 'page' # 查询第几页的key - 参数可自己设置
page_size_query_param = 'size' # 每一页显示的条数 - 参数可自己设置
max_page_size = 5 # 每页最大显示条数 - 多了不显示
from rest_framework.pagination import LimitOffsetPagination
class MyLimitOffsetPagination(LimitOffsetPagination):
default_limit = 3 # 每页条数
limit_query_param = 'limit' # 往后拿几条
offset_query_param = 'offset' # 标杆
max_limit = 5 # 每页最大几条
from rest_framework.pagination import CursorPagination
class MyCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 每一页查询的key
page_size = 2 # 每页显示的条数
ordering = '-id' # 排序字段
使用
# views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from app05_api.models import Book
from app05_api.ser import BookModelSerializer
from app06_auth.utils.app_pagination import MyPageNumberPagination,MyLimitOffsetPagination,MyCursorPagination
class BookView(APIView):
# throttle_classes = [MyThrottle,]
def get(self,request,*args,**kwargs):
book_list=Book.objects.all()
# 实例化得到一个分页器对象
page_cursor=MyPageNumberPagination()
# page_cursor=MyLimitOffsetPagination()
# page_cursor = MyCursorPagination()
book_list=page_cursor.paginate_queryset(book_list,request,view=self)
next_url =page_cursor.get_next_link()
pr_url=page_cursor.get_previous_link()
# print(next_url)
# print(pr_url)
book_ser=BookModelSerializer(book_list,many=True)
data = {'next_url':next_url,
'pr_url':pr_url,
'data':book_ser.data}
return Response(data=data)
# urls.py
from django.urls import path, re_path
from rest_framework import routers
from app06_auth import views
urlpatterns = [
path('book/', views.BookView.as_view()),
]
5.总结:
-使用:
继承了APIView的视图类中使用
page=Mypage()
# 在数据库中获取分页的数据
page_list=page.paginate_queryset(queryset对象,request,view=self)
# 对分页进行序列化
ser=BookSerializer1(instance=page_list,many=True)
# return Response(ser.data)
继承了视图子类的视图中使用
pagination_class = PageNumberPagination(配置成自己重写的,可以修改字段)
四、异常处理
REST framework提供了异常处理,我们可以自定义异常处理函数。
可以创建一个utils文件夹,里面放一个exceptions.py文件,名字随便写,然后写下面的内容
1. 自定义异常处理
# 自定义异常处理的方法
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)
# exc 异常类型 context
# 两种情况,一个是None,drf没有处理
#response对象,django处理了,但是处理的不符合咱们的要求
# print(type(exc))
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
return Response(data={'status':888,'msg':response.data.get('detail')},status=status.HTTP_400_BAD_REQUEST)
使用
# views.py
from rest_framework.response import Response
from rest_framework.views import APIView
from app05_api.models import Book
from app05_api.ser import BookModelSerializer
from app06_auth.utils.app_pagination import MyPageNumberPagination,MyLimitOffsetPagination,MyCursorPagination
class BookView(APIView):
# throttle_classes = [MyThrottle,]
def get(self,request,*args,**kwargs):
# 设置一个错误
# 1/0
book_list=Book.objects.all()
# 实例化得到一个分页器对象
page_cursor=MyPageNumberPagination()
# page_cursor=MyLimitOffsetPagination()
# page_cursor = MyCursorPagination()
book_list=page_cursor.paginate_queryset(book_list,request,view=self)
next_url =page_cursor.get_next_link()
pr_url=page_cursor.get_previous_link()
# print(next_url)
# print(pr_url)
book_ser=BookModelSerializer(book_list,many=True)
data = {'next_url':next_url,
'pr_url':pr_url,
'data':book_ser.data}
return Response(data=data)
# urls.py
from django.urls import path, re_path
from rest_framework import routers
from app06_auth import views
urlpatterns = [
path('book/', views.BookView.as_view()),
]
2. REST framework定义的异常
APIException
所有异常的父类ParseError
解析错误AuthenticationFailed
认证失败NotAuthenticated
尚未认证PermissionDenied
权限决绝NotFound
未找到MethodNotAllowed
请求方式不支持NotAcceptable
要获取的数据格式不支持Throttled
超过限流次数ValidationError
校验失败
也就是说,上面列出来的异常不需要我们自行处理了,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了。
五、响应
1. 自定义封装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)
2. 使用
from rest_framework.views import APIView
from app05_api.models import Book
from app05_api.ser import BookModelSerializer
from app06_auth.utils.app_response import APIResponse
class BookView(APIView):
# throttle_classes = [MyThrottle,]
def get(self,request,*args,**kwargs):
# 设置一个错误
# 1/0
book_list=Book.objects.all()
# 实例化得到一个分页器对象
page_cursor=MyPageNumberPagination()
# page_cursor=MyLimitOffsetPagination()
# page_cursor = MyCursorPagination()
book_list=page_cursor.paginate_queryset(book_list,request,view=self)
next_url =page_cursor.get_next_link()
pr_url=page_cursor.get_previous_link()
# print(next_url)
# print(pr_url)
book_ser=BookModelSerializer(book_list,many=True)
data = {'next_url':next_url,
'pr_url':pr_url,
'data':book_ser.data}
# return Response(data=data)
return APIResponse(data={"name": 'zs'}, token='123', aa='123456')
3.访问
http://127.0.0.1:8000/app_auth/book/