rest framework之过滤组件
一、普通过滤
1、get_queryset
get_queryset方法是GenericAPIView提供的一个方法,旨在返回queryset数据集,而过滤就是要在这个方法返回数据集之前对数据进行筛选,然后返回筛选后的数据即可,那么也就是要求需要重写这个方法:
def get_queryset(self): """ Get the list of items for this view. This must be an iterable, and may be a queryset. Defaults to using `self.queryset`. This method should always be used rather than accessing `self.queryset` directly, as `self.queryset` gets evaluated only once, and those results are cached for all subsequent requests. You may want to override this if you need to provide different querysets depending on the incoming request. (Eg. return a list of items that is specific to the user) """ assert self.queryset is not None, ( "'%s' should either include a `queryset` attribute, " "or override the `get_queryset()` method." % self.__class__.__name__ ) queryset = self.queryset if isinstance(queryset, QuerySet): # Ensure queryset is re-evaluated on each request. queryset = queryset.all() return queryset
源码中的这个方法会从视图配置中获得queryset,然后判断是否属于QuerySet类型,如果属于,就会返回这个queryset。
2、实例
- 请求API
class BookView(GenericViewSet): serializer_class = BookModelSerializer def get_queryset(self): queryset = models.Book.objects.all() title = self.request.query_params.get('title',None) if title is not None: queryset = models.Book.objects.filter(title=title).all() return queryset def list(self,request,*args,**kwargs): queryset= self.get_queryset() bs=self.get_serializer(queryset,many=True) return Response(bs.data)
路由配置:
注意如果需要过滤,url中需要加入base_name属性,并且base_name的值就是过滤参数的名称:
router=routers.DefaultRouter() router.register('books',views.BookView,base_name="title")
生成的路由:
^books/$ [name='title-list'] ^books\.(?P<format>[a-z0-9]+)/?$ [name='title-list']
请求地址:
http://127.0.0.1:8020/books/?title=语文
二、高级过滤
- 安装django-filter
pip install django-filter
- 注册django-filter
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01.apps.App01Config', 'rest_framework', 'django_filters', #注册django-filter ]
- 设置通用过滤后端
1、全局配置
REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',) }
2、局部视图设置
import django_filters.rest_framework class BookView(GenericViewSet): queryset = models.Book.objects.all() serializer_class = BookModelSerializer filter_backends = (django_filters.rest_framework.DjangoFilterBackend,)
- 指定筛选字段
如果需求都是些简单类型的筛选,那么可以在view或viewSet里面设置一个filter_fields属性,列出所有依靠筛选的字段集合。
import django_filters.rest_framework from rest_framework.viewsets import ModelViewSet class BookView(ModelViewSet): ... filter_fields = ('title',) #列出搜索字段 ...
- 进行访问
1、路由配置
from rest_framework import routers
router=routers.DefaultRouter()
router.register('books',views.BookView) #无需base_name参数
urlpatterns = [ re_path('',include(router.urls)), ]
2、生成的路由
^books/$ [name='book-list'] ^books\.(?P<format>[a-z0-9]+)/?$ [name='book-list'] ^books/(?P<pk>[^/.]+)/$ [name='book-detail'] ^books/(?P<pk>[^/.]+)\.(?P<format>[a-z0-9]+)/?$ [name='book-detail']
3、进行访问
http://127.0.0.1:8020/books/?title=语文
- FilterSet
上面所搜索的字段是一对一的关系,没有涉及到外键以及多对多字段,如果有外键或者多对多关系,可以在filter_fields中使用‘__’进行跨越:
class BookView(ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookModelSerializer filter_backends = (django_filters.rest_framework.DjangoFilterBackend,) # 列出搜索字段,其中publish__name为ForeignKey字段,authors__name为ManyToMany字段 filter_fields = ('title','publish__name','authors__name')
class Book(models.Model): title=models.CharField(max_length=32) price=models.IntegerField() pub_date=models.DateField(null=True,blank=True) publish=models.ForeignKey("Publish",on_delete=models.CASCADE) authors=models.ManyToManyField("Author") def __str__(self): return self.title
此时请求地址:
#含外键 http://127.0.0.1:8020/books/?title=语文&publish__name=北京出版社 #含多对多 http://127.0.0.1:8020/books/?title=语文&publish__name=北京出版社&authors__name=张三
但这样外键和多对多将Django的双下划线约定作为API的一部分暴露出来。如果想显式地命名过滤器参数,可以显式地将它包含在FilterSet类中:
1、定义FilterSet类
import django_filters from app01 import models class BookFilter(django_filters.rest_framework.FilterSet): publish = django_filters.CharFilter(field_name="publish__name") authors = django_filters.CharFilter(field_name="authors__name") class Meta: model = models.Book fields = ['title', 'publish', 'authors']
2、在视图中使用定义的FilterSet类
class BookView(ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookModelSerializer filter_backends = (django_filters.rest_framework.DjangoFilterBackend,) filter_class = BookFilter #使用定义的FilterSet类
此时请求地址:
http://127.0.0.1:8020/books/?title=语文&publish=北京出版社&authors=张三
3、总结
FilterSet可以实现较为复杂的过滤功能,如果是普通字段可以使用filter_fields 添加字段进行过滤,如果有外键、多对多以及范围(日期范围、价格范围)使用FilterSet.
三、其它
1、搜索过滤(SearchFilter)
支持基于简单查询参数的搜索,并且基于Django admin的搜索功能。
- 设置过滤后端
from rest_framework import filters class BookView(ModelViewSet): ... filter_backends = (filters.SearchFilter,) ...
- 设置查询字段
from rest_framework import filters class BookView(ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookModelSerializer # filter_backends = (django_filters.rest_framework.DjangoFilterBackend,) filter_backends = (filters.SearchFilter,) #凡是以下字段内容都会被搜到 search_fields = ('title','publish__name','authors__name')
当然可以通过在search_fields 前面添加各种字符来限制搜索行为:
'^' 以指定内容开始. '=' 完全匹配 '@' 全文搜索(目前只支持Django的MySQL后端) '$' 正则搜索
例如:
search_fields = ('=title',)
- 客户端访问
#将北京出版社的内容全部搜索出来 http://127.0.0.1:8020/books/?search=北京出版社 #将张三相关内容搜索出来 http://127.0.0.1:8020/books/?search=张三
通过关键词search进行搜索,可以搜索后端search_fields提供字段的内容。
SearchFilters类的默认搜索关键字为search,可以通过SEARCH_PARAM进行覆盖设置
class BookView(ModelViewSet): ... SEARCH_PARAM = 'ss' ...
2、排序筛选(OrderingFilter)
- 设置排序筛选后端
from rest_framework import filters class BookView(ModelViewSet): ... filter_backends = (filters.OrderingFilter,) ...
- 指定支持排序的字段(ordering_fields )
from rest_framework import filters class BookView(ModelViewSet): ... filter_backends = (OrderingFilter,) ordering_fields = ('title', 'id') #指定支持排序的字段 ...
- 客户端访问
通过关键字ordering请求返回的数据按照什么排序
#按照title排序 http://127.0.0.1:8020/books/?ordering=title #按照id排序 http://127.0.0.1:8020/books/?ordering=id #按照id逆序 http://127.0.0.1:8020/books/?ordering=-id #按照多个字段排序 http://127.0.0.1:8020/books/?ordering=id,title
- 默认排序
如果需要在返回的数据中已经排好序了,可以在视图中使用ordering参数:
from rest_framework import filters class BookView(ModelViewSet): queryset = models.Book.objects.all() serializer_class = BookModelSerializer filter_backends = (filters.OrderingFilter,) ordering_fields = ('title', 'id') ordering=('-id',) #默认排序
客户端访问:
http://127.0.0.1:8020/books/
返回的是已经按照id逆序排列的数据。
参考文档:https://q1mi.github.io/Django-REST-framework-documentation/api-guide/filtering_zh/#filtering
原文地址:https://www.cnblogs.com/shenjianping/p/11511978.html
- 漏洞追踪:如何检查并修复GHOST(幽灵)漏洞
- 锁的实现原理解锁的实现加锁的实现
- 幽灵漏洞(GHOST)影响大量Linux操作系统及其发行版(更新修复方案)
- openfire中mysql的前期设置
- android中最先被执行的activity
- Spring Boot微服务架构入门
- 测序文章数据上传找哪里
- Volatile实现原理实现原子性happens-before关系从happends-before规则分析可见性编译器层面实现可见性处理器层面实现可见性
- java中的toString方法
- 简单可视化-送你一双发现美的眼睛
- 享元模式
- 揭秘:针对中国移动用户的强大网银木马剖析
- 从源代码到Runtime发生的重排序编译器重排序指令重排序内存系统重排序阻止重排序
- 内存屏障保证缓存一致性优化
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 技术分享 | 一文了解高并发限流算法
- prometheus-operator 监控 k8s 外部集群
- Kubernetes 通过statefulset部署redis cluster集群
- 猿实战13——实现你没听说过的前台类目
- 猿实战14——前台类目之广告牌设置
- 猿实战15——关联你所不明白的前后台类目
- 完美解决方案-雪花算法ID到前端之后精度丢失问题
- 猿实战16——承运商之搭建你的运费基石
- List对象去重及按属性去重的8种方法-java基础总结第六篇
- 总结java创建文件夹的4种方法及其优缺点-JAVA IO基础总结第三篇
- 总结java从文件中读取数据的6种方法-JAVA IO基础总结第二篇
- 总结java中文件拷贝剪切的5种方式-JAVA IO基础总结第五篇
- 总结java中删除文件或文件夹的7种方法-JAVA IO基础总结第四篇
- 总结java中创建并写文件的五种方式-JAVA IO基础总结第一篇
- 8成以上的java线程状态图都画错了,看看这个-图解java并发第二篇