排序
排序的快速使用
1.必须是继承GenericAPIView及其子类才能是用排序
导入OrderingFilter类,from rest_framework.filters import OrderingFilter
2.在类中配置类属性
filter_backends=[OrderingFilter]
3.类中写属性
ordering_fields = ['price','id'] # 必须是表的字段
# 按照按照读书的价格和id排序
4.以后在前端,就可以访问
http://127.0.0.1:8000/api/v1/books/?ordering=price # 按price升序排
http://127.0.0.1:8000/api/v1/books/?ordering=-price # 按price降序排
http://127.0.0.1:8000/api/v1/books/?ordering=-price,id # 先按price降序排,在按id升序排
views.py
class BookListView(ViewSet, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [OrderingFilter]
ordering_fields = ['price','id']
继承VPIView写排序
过滤规则自己写
class BookListView(ViewSet, APIView):
def list(self, request):
# 从请求地址栏中取出用户过滤条件
query_params = request.query_params
# 分组查咨
obj_list = Book.objects.all().order_by(query_params.get('ordering'))
# 反序列化
ser = BookSerializer(instance=obj_list, many=True)
return Response(ser.data)
但是这个只能支持单个条件查询,如果要做多个的话需要一下步骤
class BookListView(ViewSet, APIView):
def list(self, request):
# 从请求地址栏中取出用户过滤条件
query_params = request.query_params
# 支持多个条件排序,判断如果','在ordering中就切分
if ',' in query_params.get('ordering'):
query = query_params.get('ordering').split(',')
# 分组查咨
obj_list = Book.objects.all().order_by(*query)
# 反序列化
ser = BookSerializer(instance=obj_list, many=True)
return Response(ser.data)
过滤
restful规范中,要求请求地址中带过滤条件,五个接口中,只有查询所有接口需要过滤和排序。
# 过滤,必须继承GenericAPIView及其子类,才能使用这种方法---》配置过滤类的方式
from rest_framework.filters import SearchFilter
class BookView(ViewSetMixin,ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
""" 前面配置了权限,认证,频率,这里需要取消掉"""
permission_classes = []
authentication_classes = []
throttle_classes = []
# SerchFilter内置的,固定用法,模糊匹配
# 就有了过滤功能了,指定哪个字段过滤
# search_fields = ['name'] # 可以按名字模糊匹配
filter_fields =['name','price'] # 可以按名字模糊匹配或价格模糊匹配
# 可以使用的搜索方法
1.http://127.0.0.1:8000/api/v1/books/?name=红 # name只要有红就会搜出来
2.http://127.0.0.1:8000/api/v1/books/?search=红 # name或price中只要有红就会搜出来
使用第三方django-filter实现过滤
安装django-filter
pip install django-filter
# 使用第三方djagno_filter过滤器
from django_filters.rest_framework import DjangoFilterBackend
class BookView(ViewSetMixin, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 第三方过滤器
filter_backends = [DjangoFilterBackend]
# 就有了过滤功能了,指定哪个字段过滤
# filterset_fields = ['price']
filterset_fields =['name','price'] # 支持完整匹配 name=红楼梦$price=345
# 支持的查询方式
http://127.0.0.1:8000/api/v1/books/?price=33
http://127.0.0.1:8000/api/v1/books/?price=33&name=西游记
自定义过滤类
实现名字模糊匹配,价格精准匹配,价格大于50
定义一个过滤器,继承BaseFileterBackend,重写filter_queryset方法
from rest_framework.filters import BaseFilterBackend
class CommonFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
# 在里面实现过滤,返回qs对象,就是过滤后的数据
name = request.query_params.get('name')
price = request.query_params.get('price')
price__gt = request.query_params.get('price__gt')
if name:
queryset = queryset.filter(name__contains=name)
if price:
queryset = queryset.filter(price=price)
if price__gt:
queryset = queryset.filter(price__gt=price__gt)
return queryset
views.py
class BookListView(ViewSet, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [CommonFilter]
# 不需要写字段,在CommonFilter类中已经写死了
继承APIView的写法
class BookListView(ViewSet, APIView):
def list(self, request):
name = request.query_params.get('name')
price = request.query_params.get('price')
price__gt = request.query_params.get('price__gt')
queryset = Book.objects.all()
if name:
queryset = queryset.filter(name__contains=name)
if price:
queryset = queryset.filter(price=price)
if price__gt:
queryset = queryset.filter(price__gt=price__gt)
ser = BookSerializer(instance=queryset,many=True)
return Response(ser.data)
分页
分页只针对查询所有的接口,其他四个接口不需要分页。drf内置了三个分页器,对应三种分页方式,内置的分页类不能直接使用,需要继承,定制一些参数后才能使用。一个接口只能有一种分页方式,不能混合分页方式
基本分页
分页类
from rest_framework.pagination import PageNumberPagination
class CommonPageNumberPagination(PageNumberPagination):
# page_size = api_settings.PAGE_SIZE # 每页大小,一页显示多少条
page_size = 2
page_query_param = 'page' # 分页查询,?page=1 ?page=2
page_size_query_param = 'size' # 每页最多显示多少条的查询条件
max_page_size = 5 # 每页最多显示多少条
# http://127.0.0.1:8888/api/v1/books/?page=2 # 查询第二页,显示2条
# http://127.0.0.1:8888/api/v1/books/?page=2&size=99 # 查询第二页,显示99条,但是最多显示只有5条
views.py
from .pagination import CommonPageNumberPagination
class BookListView(ViewSet, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [CommonFilter]
pagination_class = CommonPageNumberPagination # 分页方式只能选一种,不要放在列表里
偏移分页
分页类
from rest_framework.pagination import LimitOffsetPagination
class CommonLimitOffsetPagination(LimitOffsetPagination):
default_limit = 2 # 每页大小,一页显示多少条
limit_query_param = 'limit' # 每页显示的条数,查询条数,?limit=100,每页显示100条,如果不传,显示2条
offset_query_param = 'offset' # 偏移量 从第6条开始,拿30条 offset=6&limit=30
max_limit = 5 # 每页最多显示多少条
views.py
from .pagination import CommonLimitOffsetPagination
class BookListView(ViewSet, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [CommonFilter]
pagination_class = CommonLimitOffsetPagination # 分页方式只能选一种,不要放在列表里
# http://127.0.0.1:8888/api/v1/books/?limit=4&offset=1 #从第一条开始拿4条数据
游标分页
分页类
from rest_framework.pagination import CursorPagination
class CommonCursorPagination(CursorPagination):
cursor_query_param = 'cursor' # 按游标查询的查询条件
page_size = 2 # 每页大概显示多少条
ordering = 'id' # 排序规则,必须是表中字段
views.py
class BookListView(ViewSet, ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
authentication_classes = []
# filter_backends = [CommonFilter]
pagination_class = CommonCursorPagination # 分页方式只能选一种,不要放在列表里
# 游标分页不能再和排序一起使用了,但是web用的不多,app会用到
# 只能选择上一页,下一页,不能指定跳到某一页,但是速度块,针对量特别大的分页,优势大
异常处理
使用步骤
from rest_framework.response import Response
from rest_framework.views import exception_handler
# 自己写个函数,处理drf的异常和自己的异常,以后只要出现异常,都会走到它
def common_exception_handler(exc, context):
res = exception_handler(exc, context)
if res:
# 有就是drf的一场,没有就是自己的异常
# data = {'detail': exc.detail}
# return Response(data)
detail = res.data.get('detail') or 'drf异常,请联系管理员'
return Response({'code': 999, 'msg': detail})
else:
return Response({'code': 888, 'msg': '系统异常,请联系系统管理员:%s' % str(exc)})
views.py
class BookView(ViewSetMixin,APIView):
def list(self,request):
# 主动抛drf的异常
# raise APIException('我是drf异常')
# 主动抛非drf异常
raise Exception('我是非DRF异常')
books = Book.objects.all()