1 排序
排序只用于查询所有的接口
必须写在继承:GenericAPIView 类的视图类中才行
步骤
- 导入模块
from rest_framework.filters import OrderingFilter
- 在视图类中配置熟悉
filter_backends = [OrderingFilter]
- 写可以排序的字段
ordering_fields=['id','user_type']
- 使用:
- 用户类型升序排:
http://127.0.0.1:8000/user/?ordering=user_type
- 用户类型降序排:
http://127.0.0.1:8000/user/?ordering=-user_type
- 先按用户类型升序排,如果用户类型一样,再按id降序排:
http://127.0.0.1:8000/user/?ordering=user_type,-id
- 用户类型升序排:
2 过滤
过滤只用于查询所有的接口
使用过滤必须继承GenericAPIView
-
使用方式:
-
1.drf内置
2.第三方模块
3.自定义
2.1.1 drf内置
drf内置的过滤方法只能用于模糊匹配
步骤:
- 导入模块
from rest_framework.filters import SearchFilter
- 在需要过滤的视图类中添加
filter_backends = [SearchFilter]
search_fields = ['xxx','yyy']
里面填写可能需要通过过滤的字段,一定要在表中存在的 - 查询方式:
http://127.0.0.1:8000/books/?search=4
模糊匹配: 只要xxx中有4或yyy中有4都能搜出来
from rest_framework.filters import SearchFilter, OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
class BookAllView(ViewSetMixin, ListCreateAPIView):
# permission_classes = []
filter_backends = [SearchFilter]
filterset_fields = ['name','price']
queryset = Book.objects.all()
serializer_class = BookSerializer
2.1.2 第三方模块
能精准匹配,使用Django-filter
模块
步骤:
- 安装模块
- 导入类
from django_filters.rest_framework import DjangoFilterBackend
- 在需要过滤的视图类中添加
filter_backends = [DjangoFilterBackend]
filterset_fields = ['xxx','yyy']
- 使用方法
http://127.0.0.1:8000/books/?name=小王子
from django_filters.rest_framework import DjangoFilterBackend
class BookAllView(ViewSetMixin, ListCreateAPIView):
filter_backends = [DjangoFilterBackend]
filterset_fields = ['name','price']
queryset = Book.objects.all()
serializer_class = BookSerializer
2.1.3 自定义
- 导入类
from rest_framework.filters import BaseFilterBackend
- 自定义一个类,继承
BaseFilterBackend
,并写一个方法filter_queryset
- 在方法中写基于queryset进行过滤
- 在视图类中注册
filter_backends = [MyFilter]
- 使用方法同第三方模块使用
### 在过滤类中
from rest_framework.filters import BaseFilterBackend
from django.db.models import Q
class MyFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
# 基于queryset进行过滤,后过滤后返回即可
name = request.query_params.get('name')
price = request.query_params.get('price')
# 当两个都存在时匹配满足其一的条件即可
if name and price:
queryset = queryset.filter(Q(name__contains=name) | Q(price__contains=price))
if name:
queryset = queryset.filter(name__contains=name)
if price:
queryset = queryset.filter(price__contains=price)
return queryset
## 在视图类中
from .filter import MyFilter
class BookAllView(ViewSetMixin, ListCreateAPIView):
# permission_classes = []
filter_backends = [MyFilter]
# filterset_fields = ['name','price']
queryset = Book.objects.all()
serializer_class = BookSerializer
2.2 继承APIView写过滤和排序
class BookView(ViewSetMixin, APIView):
def list(self, request, *args, **kwargs):
name = request.query_params.get('name')
price = request.query_params.get('price')
queryset = Book.objects.all()
if name:
queryset = queryset.filter(name__contains=name)
if price:
queryset = queryset.filter(price__contains=price)
ser = BookSerializer(instance=queryset, many=True)
return Response(ser.data)
2.3 继承GenericAPIView写过滤类
在视图类中
from rest_framework.generics import GenericAPIView
from rest_framework.viewsets import ViewSetMixin
from .filter import MyFilter
class BookView(ViewSetMixin, GenericAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [MyFilter]
def list(self,request):
obj_list = self.filter_queryset(self.get_queryset())
ser = self.get_serializer(instance=obj_list,many=True)
return Response(ser.data)
在过滤类中
from rest_framework.filters import BaseFilterBackend
from django.db.models import Q
class MyFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
# 基于queryset进行过滤,后过滤后返回即可
name = request.query_params.get('name')
price = request.query_params.get('price')
# 当两个都存在时匹配满足其一的条件即可
if name and price:
queryset = queryset.filter(Q(name__contains=name) | Q(price__contains=price))
if name:
queryset = queryset.filter(name__contains=name)
if price:
queryset = queryset.filter(price__contains=price)
return queryset
3 分页
只针对于 查询所有接口
-
分页展现形式:
-
web : 下一页,下一页
小程序,app:上拉加载更多
必须继承 GenericAPIView
3.1 分页类
分页有不同的展现形式,写类继承不同的父类有不同的效果
PageNumberPagination
,能够自定义当前页数LimitOffsetPagination
,从某一页开始多少条数据,能够上一页下一页CursorPagination
,只能上一页和下一页,常用于app
PageNumberPagination
from rest_framework.pagination import PageNumberPagination
class CommonPageNumberPagination(PageNumberPagination):
# 展现形式
# http://api.example.org/accounts/?page=4
# http://api.example.org/accounts/?page=4&page_size=100
# 重写几个类属性
page_size = 3 # 每页显示多少条
page_query_param = 'page' # 指定第几页的key值 page=4
max_page_size = 5 # 每页最多显示几条
page_size_query_param = 'size'
# 可以指定每页显示多少条,超过最多数量时max_page_size显示
LimitOffsetPagination
from rest_framework.pagination import LimitOffsetPagination
class CommonLimitOffsetPagination(LimitOffsetPagination):
# http://api.example.org/accounts/?limit=4 # 从开始取4条
# http://api.example.org/accounts/?offset=4&limit=5 从第4条开始,取5条
default_limit = 2 # 默认每页显示几条
limit_query_param = 'limit' # 每页显示多少条的查询条件
offset_query_param = 'offset' # 从第几条开始取数据
max_limit = 5 # limit最多取5条
CursorPagination
from rest_framework.pagination import CursorPagination
class CommonCursorPagination(CursorPagination):
# 查询条件,用不到,需要有
cursor_query_param = 'cursor'
page_size = 2 # 每页显示几条
# 按id排序 这个必须是表中字段
ordering = 'id'
3.2 视图类:继承GenericAPIView使用
在视图类中如何使用写好的分页呢?
from rest_framework.viewsets import GenericViewSet
from rest_framework.mixins import ListModelMixin
from .page import CommonCursorPagination
class BookView(GenericViewSet,ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = CommonCursorPagination
3.3 视图类:继承APIView使用
from rest_framework.viewsets import ViewSetMixin
from rest_framework.views import APIView
from .page import CommonCursorPagination
class BookView(ViewSetMixin, APIView):
def list(self,request,*args,**kwargs):
book_list = Book.objects.all()
pagination = CommonCursorPagination()
page = pagination.paginate_queryset(book_list,request)
ser = BookSerializer(instance=page,many=True)
return Response(ser.data)
4 异常处理
drf全局异常处理,他会把drf的异常处理掉,统一返回格式,但是django原生的和python的都不会处理
我们要做的,无论什么异常,都返回固定格式
4.1 使用步骤
- 写一个报错执行的函数,里面传两个参数
exc、context
exc
:错误对象
context
:是一个包含有关异常上下文信息的字典
异常捕获context被传递给异常处理程序,以便在捕获和处理异常时使用这些信息。这使得可以根据异常的类型和上下文信息来实现自定义的异常处理行为。 - 执行一下原来处理drf异常的函数
导入from rest_framework.views import exception_handler
并执行,放回用变量存储起来 - 判断是否是drf的错误,如果是步骤2中的变量不为空
- 两种结果各自返回格式
- 在配置文件中导入这个函数,只要报错就会走这个函数
以后只要出了异常,都会走这个函数REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'app01.exceptions.common_exception', }
函数
from rest_framework.views import exception_handler
from rest_framework.response import Response
def common_exception(exc, context):
# 执行一下原来的exception_handler---》它能处理drf的异常,我就不用处理了
res = exception_handler(exc, context)
if not res:
return Response({'code': 999, 'msg': '非drf错误,错误信息是:%s' % str(exc)})
else:
return Response({'code': 888, 'msg': 'drf错误,错误信息是:' + res.data.get('detail')})