Drf-过滤,搜索,排序
2018-06-25 本文已影响12人
dyq666
目录
- 手动过滤
0. 概述
将这三个看似不相同的功能放到一篇文章的原因是,这三种方法的实质都是通过GET
的params
来对queryset
进行筛选。在drf中也是这么设计的,这三个模块通常在一起处理。
-
本文view的要求
Drf提供了很多种view的使用,在本文中要求使用的最低级的view是generics.GenericAPIView
。
-
变量
queryset
与方法get_queryset
通过源码查看这两者的区别。
![](https://img.haomeiwen.com/i9148872/e953446005027c3b.jpg)
从源码中可以看到
get_queryset
这个实例方法,当声明了queryset
这个变量时就返回这个值。也就是说指定了变量
queryset
后返回的查询集就固定了,当我们需要根据不同的情况返回查询集时,就需要overrideget_queryset
方法。
-
GET中的参数
在Drf中会将?xx=xxx
这类的params
存入self.query_params
。
下面是一次GET请求中,从Pycharm的Debug模式下截取的参数。(本次请求中url
是以?price_min=20
结尾的)
![](https://img.haomeiwen.com/i9148872/135095ecc585dc3c.jpg)
1. 手动过滤
-
完成view中的过滤逻辑部分
这里完成的功能是:获取大于等于price_min
的数据。
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = StandardResultsSetPagination
# 重写方法(上面的配置都没使用)
def get_queryset(self):
price_min = self.query_params.get("price_min", None)
if price_min:
return Goods.objects.filter(shop_price__gt=int(price_min))
return Goods.objects.all()
- 可能是版本问题(这里我的drf版本是
3.82
),如果不设置queryset
就会报错(所以这里我们将queryset
随便设置为一个QuerySet)。 - override
get_queryset
方法。 - 获取
query_params
中的过滤条件price_min
。 - 如果有
price_min
就返回过滤(__gt
是Django提供的大于等于的过滤方法)的查询集,否则返回整个查询集。
-
优化一下逻辑部分的代码
由于Drf强制的要求写queryset变量,正好直接利用这个变量。(仔细想想强制要求还是很好的!而且Drf还要求了它必须是一个查询集!)
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
queryset = Goods.objects.all()
serializer_class = GoodsSerializer
pagination_class = StandardResultsSetPagination
# 直接通过实例变量使用类变量queryset
def get_queryset(self):
price_min = self.request.query_params.get("price_min", "0")
if price_min:
return self.queryset.filter(shop_price__gt=int(price_min))
return self.queryset
2. Drf-过滤的基础使用
-
概述
由于第三方包django-filter
已经非常成熟了,并且支持Drf,所以Drf没有再实现过滤功能。
-
安装
pip install django-filter
-
在
settings.py
引入应用
INSTALLED_APPS = [
'django_filters',
]
-
在
settings.py
全局配置过滤后端
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
}
-
也可以在
views.py
中配置
配置过滤的后端和过滤的属性。
filter_backends = (DjangoFilterBackend, )
filter_fields = ('shop_price',)
-
使用filter
可以直接在url增加后缀?shop_price=xx
-
BrowserAPI也提供了过滤功能
![](https://img.haomeiwen.com/i9148872/967d2d316a056978.jpg)
3. 进阶使用(filter_class)
-
创建
filter_class
通常先在对应的应用目录下创建filters.py
。
下面代码完成了对shop_price字段进行大于等于的查询,然后定义这个query_param的名字为min_price。
import django_filters
from .models import Goods
class GoodsFilter(django_filters.rest_framework.FilterSet):
min_price = django_filters.NumberFilter(name='shop_price', lookup_expr='gt')
class Meta:
model = Goods
fields = ['min_price']
- 继承类(一定要继承Drf中的类
django_filters.rest_framework.FilterSet
,不要继承django_filters.FilterSet
) - 设置过滤条件,过滤条件中有两个重要的参数:
- name 代表Model中的字段
- lookup_expr而是djangoORM查询提供的查询方法(
gt
等于model.objects.filter(xx__gt=xx)
)。
-
views.py
中使用filter_class
from .filters import GoodsFilter
class xxView(xxxView):
filter_class = GoodsFilter
-
常用的filter技巧
- 常用的lookup_expr
- 比较
gt, lt, gte, lte - 大于,小于,大于等于,小于等于 - 查询
icontains 忽略大小写+子字符串
-
查询外键的属性
外键名__外键属性 -
使用方法进行过滤
指定参数method
。
class xxFilter:
top_category = django_filters.NumberFilter(method='top_category_filter')
def top_category_filter(self, queryset, name, value):
"""
根据商品类别的id(肯定是一类目的)获取该类目下面所有的商品(包括每个子类目)
1\. 参数分别为,过滤到现在的查询集,?a=b中的a和b
"""
return queryset.filter(Q(category_id=value) |
Q(category__parent_category_id=value) |
Q(category__parent_category__parent_category_id=value))
4. 搜索
-
概述
搜索功能使用的是Drf自带的内容。Drf将搜索功能也融入了filter中,所以配置与filter类似。
-
views.py
中使用
在filter_backends中加入搜索功能。
filter_backends= (DjangoFilterBackend, filters.SearchFilter)
指明查询的字段即可。
search_fields = ('name',)
-
正则化查询
提供了下面几种正则化的查询方式。
![](https://img.haomeiwen.com/i9148872/387f09a1ffadeea5.jpg)
比如准确查询就用
=name
-
url中的使用
xxx/?search=xx
5. 排序
基本与搜索相同!
filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
ordering_fields = ('name',)
-
url中的使用
xxx/?ordering=xx