drf过滤和排序及异常处理的包装


目录
  • 过滤和排序(4星)
    • 内置过滤类
      • 使用方法
    • 第三方插件过滤(可以有and关系)
      • 使用方法
    • 自定义过滤类
      • 使用方法
      • 源码分析
    • 内置排序类(既有排序,又有过滤)
      • 使用方法
      • 过滤加排序
  • 异常处理(4星)
    • 使用方法
    • 源码分析

过滤和排序(4星)

查询所有才需要过滤(根据过滤条件),排序(按某个规律排序) 使用前提: 必须继承的顶层类是GenericAPIView

内置过滤类

内置过滤类使用,在视图类中配置,是模糊查询 使用前提: 必须继承的顶层类是GenericAPIView

使用方法

设置

from rest_framework.filters import SearchFilter

class BookAPIView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer
    # 在视图类中配置 最顶层的类至少是GenericAPIView
    filter_backends = [SearchFilter, ]  # 设置这个
    # 过滤条件,按名字过滤
    search_fields = ['title', 'price']  # 取决于models里的字段

查询

http://127.0.0.1:8000/books/?search=22   # 书名中或者价格中有22就能查询出来

第三方插件过滤(可以有and关系)

下载模块pip3 install django-filter 并且这个是精准查询 使用前提: 必须继承的顶层类是GenericAPIView

使用方法

注册

INSTALLED_APPS = [
		...
    'django_filters',
]

设置

from django_filters.rest_framework import DjangoFilterBackend

class BookAPIView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer
    filter_backends = [DjangoFilterBackend, ]  # 写上面导入的类
    # 过滤条件,按名字过滤
    filter_fields =['name', 'price']

查询

http://127.0.0.1:8000/books/?name=红  # 返回空列表
http://127.0.0.1:8000/books/?name=红楼梦
http://127.0.0.1:8000/books/?name=红楼梦&price=33  # &符号是and关系
http://127.0.0.1:8000/books/?name=红楼梦&price=32  # 返回空列表

image

image

自定义过滤类

使用方法

写一个类,继承BaseFilterBackend 基类,重写filter_queryset方法,返回的qs对象,是过滤后的对象 使用前提: 必须继承的顶层类是GenericAPIView

# 在自己创建的untils.py中
from rest_framework.filters import BaseFilterBackend

class BookFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        query = request.query_params.get('title')
        if query:
            queryset = queryset.filter(title__contains=query)  # 根据过滤条件筛选数据
        return queryset

# 在views.py中
from .untils import BookFilter

class BookAPIView(GenericViewSet, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer
    filter_backends = [BookFilter, ]  # 设置自定义过滤类  自己定义的过滤类就不需要写类属性了

查询

http://127.0.0.1:8000/books/?title=红  # 模糊匹配 ,自己定义的

image

源码分析

#### 源码分析----》GenericAPIView----》查询所有,调用了list---》self.filter_queryset(self.get_queryset())----》查看GenericAPIView的filter_queryset方法:
    def filter_queryset(self, queryset):
        for backend in list(self.filter_backends): # 去视图类里取自定义过滤类名
# 自定义过滤类名实例化得到对象调用filter_queryset方法 而这个就是我们自己写的方法,返回值就是过滤后的数据
            queryset = backend().filter_queryset(self.request, queryset, self)
        return queryset

内置排序类(既有排序,又有过滤)

使用前提: 必须继承的顶层类是GenericAPIView

使用方法

设置

from rest_framework.filters import OrderingFilter,SearchFilter

class BookAPIView(ModelViewSet):
    queryset = Book.objects.all()
    serializer_class = BookModelSerializer
    filter_backends = [SearchFilter, OrderingFilter]
    # 过滤条件,按名字过滤
    search_fields = ['title', 'price']
    # 按哪个字段排序
    ordering_fields = ['price', 'id']

查询

http://127.0.0.1:8000/books/?ordering=price,-id
# 上面这句话的意思是按价格升序,如果遇到相同的,就按id降序

image

过滤加排序

过滤和排序可以同时用--->因为他们本质是for循环一个个执行,所有优先使用过滤,再使用排序

filter_backends = [SearchFilter,OrderingFilter]
ordering_fields=['price','id']
search_fields=['name','author']

查询

http://127.0.0.1:8000/books/?search=22&ordering=-id

image

异常处理(4星)

全局统一捕获异常,返回固定的格式 {code:999,msg:'未知错误'}(类似这种格式)

使用方法

在一个新的py文件内:

from rest_framework.views import exception_handler  # 默认没有配置,出了异常会走它
from rest_framework.response import Response
def common_exception_handler(exc, context):
    # 取出出错的IP,可以不用
    print(context['request'].META.get('REMOTE_ADDR'))
    ######################################重点##########################################
    # exception_handler方法会返回Response对象或者None
    res = exception_handler(exc, context)
    if res:  # 这表示已经处理了异常,它只处理APIExcepiton的异常
        res = Response(data={'code': 998, 'msg': res.data.get('detail', '服务器异常')})
    else: # 返回None,表示是出了不知道的异常
        res = Response(data={'code': 999, 'msg': str(exc)})
    # 注意:在这里,可以记录日志---》只要走到这,说明程序报错了,记录日志,以后查日志---》尽量详细
    # 出错时间,错误原因,哪个视图类出了错,什么请求地址,什么请求方式出了错
    request = context.get('request')  # 这个request是当次请求的request对象
    view = context.get('view')  # 这个viewt是当次执行的视图类对象
    # 下面的打印只是举例让你看日志的大概数据
    print('错误原因:%s,错误视图类:%s,请求地址:%s,请求方式:%s' % (str(exc), str(view), request.path, request.method))
    return res

配置文件配置:

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'app01.untils.common_exception_handler'
}

源码分析

image

image

image

image

image

image