一. 过滤组件

1 内置过滤组件SearchFilter

# 缺点: 外键字段的搜索操作将会抛出异常: Related Field got invalid lookup: icontains

# 1)在视图文件views.py中导入drf的搜索组件
from rest_framework.filters import SearchFilter # 2)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [SearchFilter] # 3)配置视图类关联的Model表参与搜索的字段
search_fields = ['name', 'id'] # 4)前台访问该群查接口,采用拼接参数方式用search关键字将搜索目标提供给后台
http://127.0.0.1:8000/course/free/?search=2 # id或name中包含2的所有结果

2 第三方过滤组件django-filter

使用

1. 安装:pip3 install django-filter
2. 注册: settings.py中注册
INSTALLED_APPS = [
...
'django_filters', # 需要注册应用,
] 3. 全局配置 或者 局部配置
全局配置: 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',)
局部配置:
指定所有字段: filterset_fields = '__all__'
指定固定字段: filterset_fields = ['name', ...] # 提示: 可以元组, 也可以是列表
# 介绍: 争对django内置搜索组件的拓展, 在django内置的基础之上还拓展了外键字段的过滤功能.
# 前提:安装django-filter插件
pip install django-filter (注意: 不要安装成了django-filters) """方式一"""
# 1)在视图文件views.py中导入django-filter的功能组件
from django_filters.rest_framework import DjangoFilterBackend # 2)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [DjangoFilterBackend] # 3)配置视图类关联的Model表可以分类的字段(通常是可以分组的字段)
filterset_fields = ['course_category'] # 4)前台访问该群查接口,采用拼接参数方式用分类course_category字段将分类条件提供给后台
http://127.0.0.1:8000/course/free/?course_category=1 # 拿课程分类1下的所有课程 '''方式二'''
# 1)自定义过滤类继承django-filter插件的FilterSet类,绑定Model表,并设置分类字段
from django_filters.filterset import FilterSet
from . import models
class CourseFilterSet(FilterSet):
class Meta:
model = models.Course
fields = ['course_category'] # 2)在视图文件views.py中导入django-filter的功能组件及自定义的过滤类
from django_filters.rest_framework import DjangoFilterBackend
from .filters import CourseFilterSet # 3)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [DjangoFilterBackend] # 4)配置视图类关联的自定义过滤类
filter_class = CourseFilterSet # 5)前台访问该群查接口,采用拼接参数方式用分类course_category字段将分类条件提供给后台
http://127.0.0.1:8000/course/free/?course_category=1 # 拿课程分类1下的所有课程

3. django-filter实现区间过滤

# 1)自定义过滤类继承django-filter插件的FilterSet类,绑定Model表,并设置自定义区间规则字段
from django_filters.filterset import FilterSet
from . import models
class CourseFilterSet(FilterSet):
# 区间过滤: students学生中总人数要大于等于min_students, 要小于等于max_students. [min_students, max_students]
max_students = filters.NumberFilter(field_name='students', lookup_expr='lte')
min_students = filters.NumberFilter(field_name='students', lookup_expr='gte') class Meta:
model = Course
fields = ['course_category', 'students', 'min_students', 'max_students'] # 2)在视图文件views.py中导入django-filter的功能组件及自定义的过滤类
from django_filters.rest_framework import DjangoFilterBackend
from .filters import CourseFilterSet # 3)将搜索组件配置给群查接口视图类的filter_backends
filter_backends = [DjangoFilterBackend] # 4)配置视图类关联的自定义过滤类
filter_class = CourseFilterSet # 5)前台访问该群查接口,采用拼接参数方式用自定义区间规则字段将区间条件提供给后台
http://127.0.0.1:8000/course/free/?min_students=230&max_students=250 # 获取学生总人数230~250之间的数据

4. 自定义过滤

# filters.py
from rest_framework.filters import BaseFilterBackend class CustomFilter(BaseFilterBackend):
def filter_queryset(self, request, queryset, view):
# 老师的模糊匹配
name = request.GET.get('teacher')
if not name:
return queryset
teacher_queryset = queryset.filter(teacher__name__contains=name)
return teacher_queryset # views.py
# 自定义过滤: 通过老师名进行模糊匹配
filter_backends = [CustomFilter]

5. 注意

django-filter的安装可能会出现django版本最低要求问题,  如果下载最新版本的django-filter
如果使用的是django 1.11版本会自动升级到3.x,并使用filterset_fileds

二. 排序组件

1. 全局配置 局部配置

# 全局配置
# 排序
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('rest_framework.filters.OrderingFilter')
} # 过滤 和 排序
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend', 'rest_framework.filters.OrderingFilter')
} # 局部配置
# 排序
from rest_framework.filters import OrderingFilter
filter_backends = [OrderingFilter] # 注意: 如果这样就会覆盖全局配置配置的过滤 # 过滤 和 排序
from rest_framework.filters import OrderingFilter
from django_filters.rest_framework import DjangoFilterBackend
filter_backends = [OrderingFilter, DjangoFilterBackend]
filterset_fields = '__all__'

2. 代码实例

class TextView7(ListAPIView):
# 局部将全局可能配置的认证+权限+频率禁用
authentication_classes = []
permission_classes = []
throttle_classes = [] # 局部配置排序组件.
# 注意: 如果要过滤和排序, 需要注意的是如果全局配置了过滤, 需要在声明排序的基础之上再什么过滤. 因为filter_backends的局部指定会覆盖过滤的配置.
# filter_backends = [OrderingFilter, DjangoFilterBackend, ] # 提示: 2者之间没有顺序
filter_backends = [DjangoFilterBackend, OrderingFilter] queryset = models.Book.objects.all()
serializer_class = BookModelSerializer filterset_fields = ['name', 'price'] # 可以用列表, 也可以用元组
from rest_framework.generics import ListCreateAPIView
from app01 import models
from app01.ser import BookSerializer from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import OrderingFilter # 排序
class BookView1(ListCreateAPIView):
# authentication_classes = [] queryset = models.Book.objects.all()
serializer_class = BookSerializer
filter_backends = [OrderingFilter, DjangoFilterBackend]
filterset_fields = ['title', ]
ordering_fields = ('id', 'price') # # 127.0.0.1:8000/books1/?ordering=-id
# -id 表示针对id字段进行倒序排序
# id 表示针对id字段进行升序排序 # 可以结合过滤一起使用

3. 总结

# 过滤导入
from django_filters.rest_framework import DjangoFilterBackend
# 排序导入
from rest_framework.filters import OrderingFilter
# 注意问题
它们2个全局配置都是共用一个配置路径, 如果局部指定了就会将全局配置的对应项所有的覆盖

三. 异常处理

1. 从源码分析到如何实现自定义异常处理

# 思路: 发现有些错误被drf捕获了, 而有些错误会交给django自己处理, 这是为什么呢? 源码分析一波

# 查找路径: APIView -> dispatch -> try..except -> handle_exception

# 源码分析:
try:
self.initial(request, *args, **kwargs) # Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed response = handler(request, *args, **kwargs) except Exception as exc:
response = self.handle_exception(exc) # 这里 1. 异常的捕获范围: 注意, 并不是所有位置的异常出可以捕获. 例如: 自定义视图中的类中抛出的异常就不行
self.initial(request, *args, **kwargs)
认证: self.perform_authentication(request)
提示: 不会捕获自定义的认证类. 因此perform_authentication做的事情就是request.user赋值
权限: self.check_permissions(request)
频率: self.check_throttles(request)
自定义视图类中的方法:
response = handler(request, *args, **kwargs)
2. 关键实现 handle_exception方法
def handle_exception(self, exc):
# 1) 这里的在认证失败的时候会走
if isinstance(exc, (exceptions.NotAuthenticated,
exceptions.AuthenticationFailed)):
# WWW-Authenticate header for 401 responses, else coerce to 403
auth_header = self.get_authenticate_header(self.request) if auth_header:
exc.auth_header = auth_header
else:
exc.status_code = status.HTTP_403_FORBIDDEN # 2) 这里就是通过配置文件配置的路径, 拿到处理异常的函数, 内部就一句代码: self.settings.EXCEPTION_HANDLER
'''
def get_exception_handler(self):
"""
配置文件导入的内容:
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',
"""
return self.settings.EXCEPTION_HANDLER
'''
exception_handler = self.get_exception_handler() # 3) 获取异常的处理的上下文内容, 本质里面就是获取操作的视图对象的结果
'''
def get_exception_handler_context(self):
return {
'view': self,
'args': getattr(self, 'args', ()),
'kwargs': getattr(self, 'kwargs', {}),
'request': getattr(self, 'request', None)
}
'''
context = self.get_exception_handler_context() # 4) 将刚刚从配置文件中导入的视图函数传参调用
'''
exc: 这里的exc是APIView中定义的dispatch中传过来的异常对象
context: 这里的context是对出现异常对象的上下文捕获
'''
response = exception_handler(exc, context) # 5) 关键转折:
'''
这里就是通过在drf提供的exception_handler函数处理的返回值结果来判断时候交给django自己处理.
如果response的返回值是None就会交给django处理了, 现在我们要的就是在exception_handler函数执行完毕以后将返回值进行判断,
并且返回的结果不再是None, 而应该是response对象
'''
if response is None:
self.raise_uncaught_exception(exc) response.exception = True
return response # 步骤:
1. 先新建一个.py文件存放自定义的异常处理函数
2. 在drf提供的默认配置文件中导入exception_handler函数的
3. 在自定义异常处理函数中先将exception_handler传入让drf先处理一番, 根据返回的结果为None是来执行自己的判断.
如果返回不为None也不应该直接将原本的response对象直接返回, 可以自己封装一个符合restful规范的类用来继承Response类
将原本的response对象中的返回结果通过 response.data.get('detail') 方法获取
4. settings.py文件中配置自定义的exception_handler函数的路径
'EXCEPTION_HANDLER': 'app01.app_auth.custom_exception_handler',

2. 代码实例

自定义utils.py

from rest_framework.views import exception_handler
from rest_framework import status from rest_framework.response import Response class APIResponse(Response):
def __init__(self, code=1000, messages='成功', results=None, error=None,
status=None,
template_name=None, headers=None,
exception=False, content_type=None, **kwargs):
data = {
'code:': code,
'messages:': messages,
}
print('error:', error)
print('results:', results)
if results:
data['results'] = results
if error:
data['error'] = error
data.update(kwargs) super().__init__(data=data, status=status,
template_name=template_name, headers=headers,
exception=exception, content_type=content_type) def custom_exception_handler(exc, context):
"""
:param exc: 这里的exc是APIView中定义的dispatch中传过来的异常对象
try:
...
except Exception as exc:
response = self.handle_exception(exc)
:param context: 这里的context是对出现异常对象的上下文捕获
查找: handle_exception -> get_exception_handler_context
def get_exception_handler_context(self):
return {
'view': self,
'args': getattr(self, 'args', ()),
'kwargs': getattr(self, 'kwargs', {}),
'request': getattr(self, 'request', None)
}
:return: 这里返回Response对象, 本来drf没有处理的的异常会交给django处理, 但是我们捕获这种异常, 规定成统一的处理. 让drf处理. 注意!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
这里可以捕获的异常范围由以下源码得知:
try:
self.initial(request, *args, **kwargs) # Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc) 捕获范围:
self.initial(request, *args, **kwargs)
认证: self.perform_authentication(request)
提示: 不会捕获自定义的认证类. 因此perform_authentication做的事情就是request.user赋值
权限: self.check_permissions(request)
频率: self.check_throttles(request)
自定义视图类中的方法:
response = handler(request, *args, **kwargs)
"""
obj = None
response = exception_handler(exc, context)
# 注意: exc, context都不是可json序列化的格式, 需要转换成字符串类型.
if not response:
# 自己的处理
if isinstance(exc, AttributeError):
obj = APIResponse(2000, '失败', error=str(exc), results=str(context), status=status.HTTP_403_FORBIDDEN)
elif isinstance(exc, ImportError):
obj = APIResponse(2002, '失败', error=str(exc), results=str(context), status=status.HTTP_403_FORBIDDEN)
elif isinstance(exc, TypeError):
obj = APIResponse(2003, '失败', error=str(exc), results=str(context), status=status.HTTP_403_FORBIDDEN)
elif isinstance(exc, Exception):
obj = APIResponse(2004, '失败', error=str(exc), results=str(context), status=status.HTTP_403_FORBIDDEN)
else:
# 在drf处理的基础之上再次处理
obj = APIResponse(2005, '失败', error=response.data.get('detail'), results=str(context),
status=status.HTTP_403_FORBIDDEN)
return obj

3. 总结

1. 导入需要在drf提供的默认函数的基础之上的函数
from rest_framework.views import exception_handler
2. 自定义异常处理函数2个参数exc, context
3. 先让drf处理一波, 处理它处理不完的, 或者 在他处理完的基础之上拓展, 通过response返回结果来进行区分
提示: 可以通过 response.data.get('detail') 获取drf处理完的对象中返回的响应信息

4. 注意

配置文件中配置自定义的异常处理函数时, drf提供的exception_handler的导入会与在同一个文件中自定义的认证类 或者 自定义的权限类的导入起冲突.
自定义的异常的处理代码逻辑最好新建一个纯净的.py文件存放

5. 快速使用

from rest_framework.views import exception_handler
from rest_framework.response import Response class CommonResponse(Response):
def __init__(self, code=1000, messages='ok', results=None,
status=None, template_name=None, headers=None,
exception=False, content_type=None,
**kwargs):
data = {
'code': code,
'messages': messages,
}
data.update(kwargs)
if results:
data['results'] = results
super().__init__(data=data, status=status,
template_name=template_name, headers=headers,
exception=exception, content_type=content_type) def common_exception_handler(exc, context):
response = exception_handler(exc, context)
if not response:
obj = CommonResponse(code=2000, messages='error', results=str(exc))
else:
obj = CommonResponse(code=2000, messages='error', results=response.data)
return obj

settings.py全局配置(所有drf的异常,都会走这里)

'EXCEPTION_HANDLER': 'app01.app01_auth.my_exception_handler',

drf(过滤、排序、异常)的更多相关文章

  1. DRF 过滤排序分页异常处理

    DRF 中如何使用过滤,排序,分页,以及报错了如何处理?10分钟get了~

  2. day74:drf:drf其他功能:认证/权限/限流/过滤/排序/分页/异常处理&自动生成接口文档

    目录 1.django-admin 2.认证:Authentication 3.权限:Permissions 4.限流:Throttling 5.过滤:Filtering 6.排序:OrderingF ...

  3. drf-day7——认证组件、权限组件、频率组件、过滤排序、分页

    目录 一.认证组件 1.1 登录接口 1.2 认证组件使用步骤 1.3 整体代码 1.4认证时cookie的获取方式 二.权限组件 2.1需求分析: 2.2 权限的使用 2.3代码 三.频率组件 3. ...

  4. ch7-列表渲染(v-for key 数组更新检测 显示过滤/排序结果)

    1 说明 我们用 v-for 指令根据一组数组的选项列表进行渲染. v-for 指令需要以 item in items 形式的特殊语法, items 是源数据数组并且 item 是数组元素迭代的别名. ...

  5. CopyOnWriteArrayList集合排序异常问题

    1.集合自定义排序实现 对List集合的自定义排序想必大家都知道要使用如下的方式,通过实现Comparator接口并实现compare方法来实现. /** * * @方法名 changeChain * ...

  6. Vue数组更新及过滤排序

    前面的话 Vue为了增加列表渲染的功能,增加了一组观察数组的方法,而且可以显示一个数组的过滤或排序的副本.本文将详细介绍Vue数组更新及过滤排序 变异方法 Vue 包含一组观察数组的变异方法,它们将会 ...

  7. AngularJS过滤排序思路

    本篇主要整理使用AngularJS进行过滤排序的思路. 在controller中,$scope的persons字段存储数组. $scope.persons = [ { "name" ...

  8. 三 drf 认证,权限,限流,过滤,排序,分页,异常处理,接口文档,集xadmin的使用

    因为接下来的功能中需要使用到登陆功能,所以我们使用django内置admin站点并创建一个管理员. python manage.py createsuperuser 创建管理员以后,访问admin站点 ...

  9. DRF之过滤排序分页异常处理

    一.过滤 对于列表数据要通过字段来进行过滤,就需要添加 django-filter 模块 使用方法: # 1.注册,在app中注册 settings.py INSTALLED_APPS = [ 'dj ...

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

    过滤和排序(4星) 查询所有才需要过滤(根据过滤条件),排序(按某个规律排序) 使用前提: 必须继承的顶层类是GenericAPIView 内置过滤类 内置过滤类使用,在视图类中配置,是模糊查询 使用 ...

随机推荐

  1. 案例:记录一则强制开库遭遇ORA-16433的处理过程

    客户的一套开发环境,大概了解到的背景是清理空间时redo被运维人员当作log误删除,一线同事先接手处理,过程中遇到问题升级到我这里继续分析. 接手后,数据库处于mount状态,之前恢复过程中已经做过r ...

  2. CF1295

    A 用计算器式显示数字,可以显示 \(n\) 段.可以显示的最大数字是多少? 如果用了一个需要至少四段的数字,一定不如把这个替换成两个 \(1\) 好. 如果一共可以用偶数个,一定是全部 \(1\). ...

  3. Pandas分析泰坦尼克号生还比例

    提出问题 影响乘客生还的因素很多,这里只对乘客的性别.年龄.乘客等级.这三个因素感兴趣, 看看这四个因素是否会影响乘客的生还率. 1.性别是否会影响生还率 2.年龄是否会影响生还率 3.乘客等级会否会 ...

  4. Power BI 15 DAY

    业务(表结构)数据分析 1.业务理解 准确 全面 2.数据收集 了解需要用到的数据有哪些 5W2H 结构化数据 SQL.通过查询获取数据库资源 多源表结构数据 企业数据库数据 文本文件数据 Excel ...

  5. Innodb存储引擎之锁

    目录 一.概述 二.lock 与 latch 三.Innodb存储引擎中的锁 锁 一致性非锁定读 一致性锁定读 自增长与锁 外键与锁 四.锁的算法 锁的算法 Phantom Problem 幻读问题 ...

  6. 【手写信息搜集工具】ThunderSearch 闪电搜索器

    ThunderSearch 闪电搜索器 项目地址:github Windows打包版 利用ZoomEye的官方api,结合开发文档,做了这么一个GUI界面的搜索器.目前支持查询host_search ...

  7. 案例分享:Qt便携式致病菌快速检测仪(账号管理、实验过程、二维图表、历史数据、通讯管理、实验报告、中英文等等)

    需求   根据提供的用户原型设计.ui设计.通讯协议研发便携式致病菌快速检测仪器软件.  100%还原ui.   基本主功能(推荐visio:★★★☆☆,前期主流程需求整理)          Dem ...

  8. Django关于StreamingHttpResponse与FileResponse响应文件或视频的下载请求

    StreamingHttpResponse from django.http import StreamingHttpResponse StreamingHttpResponse(streaming_ ...

  9. Android底层渲染原理

    Overview多年前Android的UI流畅性差的问题一直饱受诟病,Google为了解决这个问题开发了Project Butter项目,也就是黄油计划,期望彻底改善Android系统的流畅性.这是A ...

  10. SpringCloud组件:Feign之日志输出

    目录 Feign之日志输出 Feign日志输出说明 前期准备 构建项目 tairan-spring-cloud-feign-logger配置 源码位置 Feign之日志输出 在我们日常开发过程中,经常 ...