排序
排序的快速使用
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 = BookSerializerfilter_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 = BookSerializerfilter_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 = 2page_query_param = 'page' # 分页查询,?page=1 ?page=2page_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 = BookSerializerfilter_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=30max_limit = 5 # 每页最多显示多少条
views.py
from .pagination import CommonLimitOffsetPagination
class BookListView(ViewSet, ListAPIView):queryset = Book.objects.all()serializer_class = BookSerializerfilter_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 = BookSerializerauthentication_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()