欢迎访问我的博客专题
源码可访问 Github 查看
DRF过滤商品列表
GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet)
继承的viewsets.GenericViewSet
(GenericViewSet(ViewSetMixin, generics.GenericAPIView)
)继承的GenericAPIView(views.APIView)
提供了一个get_queryset()
方法,可以通过这个方法,进行过滤
# 源码内容
def get_queryset(self):
queryset = self.queryset
if isinstance(queryset, QuerySet):
# Ensure queryset is re-evaluated on each request.
queryset = queryset.all()
return queryset
使用get_queryset查询函数
修改 views.py 中的视图
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
显示商品列表
"""
queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
def get_queryset(self):
return Goods.objects.filter(shop_price__gt=120)
筛选商店价格大于120元的数据,刷新 http://127.0.0.1:8000/goods/
![](https://img.haomeiwen.com/i5730845/ddd8233ca80e613b.png)
可以看到总的数量已经发生变化。
获取url的参数request.query_params,传递价格区间
参考 https://www.django-rest-framework.org/api-guide/requests/#query_params
request.query_params
是request.GET
的更正确的同义词。
为了使代码更清晰,建议使用request.query_params
而不是Django的标准request.GET。这样做将有助于保持代码库更加正确和明显——任何HTTP方法类型都可能包含查询参数,而不仅仅是GET请求。
修改 views.py 增加过滤参数
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
显示商品列表
"""
queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
def get_queryset(self):
queryset = self.queryset
# 传递价格区间的参数
price_min = self.request.query_params.get('price_min')
if price_min:
queryset = queryset.filter(shop_price__gte=price_min)
return queryset
现在访问 http://127.0.0.1:8000/goods/?price_min=160 指定过滤条件,最小价格为160
![](https://img.haomeiwen.com/i5730845/b428e13dac5cd8c6.png)
但是如果过滤条件很多的情况,就需要加入很多的筛选,也就是get_queryset
函数需要获取每个参数及其值,然后在查询集进行过滤,比较麻烦
使用DjangoFilterBackend
参考 https://www.django-rest-framework.org/api-guide/filtering/#djangofilterbackend
django-filter
库包含一个DjangoFilterBackend
类,它支持REST框架的高度可定制字段过滤。
要使用DjangoFilterBackend
,首先安装pip install django-filter
。然后将django_filters
添加到Django的INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
# 添加drf应用
'rest_framework',
'django_filters',
# 注册富文本编辑器ckeditor
'ckeditor',
# 注册富文本上传图片ckeditor_uploader
'ckeditor_uploader',
'users.apps.UsersConfig',
'goods.apps.GoodsConfig',
'trade.apps.TradeConfig',
'user_operation.apps.UserOperationConfig'
]
修改 views.py 增加商品列表的过滤器
from django_filters.rest_framework import DjangoFilterBackend
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
显示商品列表
"""
queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend,) # 将过滤器后端添加到单个视图或视图集
filterset_fields = ('name', 'goods_desc', )
当搜索一个name完整名称显示如下,这时url为 http://127.0.0.1:8000/goods/?name=%E6%96%B0%E9%B2%9C%E6%B0%B4%E6%9E%9C%E7%94%9C%E8%9C%9C%E9%A6%99%E8%84%86%E5%8D%95%E6%9E%9C%E7%BA%A6800%E5%85%8B&goods_desc= :
![](https://img.haomeiwen.com/i5730845/c9313ae552450551.png)
但是,如果要模糊搜索,这时候url为 http://127.0.0.1:8000/goods/?name=%E6%B0%B4%E6%9E%9C&goods_desc=
![](https://img.haomeiwen.com/i5730845/2ac401f8ab9f519f.png)
这一看到,是过滤不出结果的,因为这是一个 等式 的匹配
可以查看官方文档 https://django-filter.readthedocs.io/en/master/guide/rest_framework.html
如何自定义filter,可以参考 https://django-filter.readthedocs.io/en/master/guide/rest_framework.html#adding-a-filterset-with-filterset-class
首先,在应用下创建 filters.py 文件,用于放置所有的filter
![](https://img.haomeiwen.com/i5730845/10775ada8e427214.png)
修改添加以下内容
# filters.py
from django_filters import rest_framework as filters
from .models import Goods
class GoodsFilter(filters.FilterSet):
"""
商品的过滤类
"""
name = filters.CharFilter(field_name='name', lookup_expr='contains') # 包含关系,模糊匹配
goods_desc = filters.CharFilter(field_name='name', lookup_expr='contains')
min_price = filters.NumberFilter(field_name="shop_price", lookup_expr='gte') # 自定义字段
max_price = filters.NumberFilter(field_name="shop_price", lookup_expr='lte')
class Meta:
model = Goods
fields = ['name', 'goods_desc', 'min_price', 'max_price']
例如上方的field_name='name', lookup_expr='contains'
就类似于Django中queryset.filter(name__contains=xxx)
,field_name
需和模型中的字段保持一致,而前面的字段就是url中的参数。Meta
需要指定操作的模型名以及对应的字段。
修改 views.py ,添加自定义过滤类filterset_class = GoodsFilter
from django_filters.rest_framework import DjangoFilterBackend
from .filters import GoodsFilter
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
显示商品列表
"""
queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend,) # 将过滤器后端添加到单个视图或视图集
filterset_class = GoodsFilter
![](https://img.haomeiwen.com/i5730845/4cd7477f5077fb26.png)
输入字段进行过滤,这时候url为: http://127.0.0.1:8000/goods/?name=%E6%B0%B4%E6%9E%9C&goods_desc=&min_price=150&max_price=180
使用SearchFilter
参考: https://www.django-rest-framework.org/api-guide/filtering/#searchfilter
搜索最适合模糊匹配
SearchFilter
类支持简单的基于查询参数的搜索,并且基于Django管理员的搜索功能。
search_fields
属性应该是模型中文本类型字段的名称列表,例如CharField或TextField。
修改 views.py
from rest_framework import viewsets, filters
from django_filters.rest_framework import DjangoFilterBackend
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
显示商品列表
"""
queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, filters.SearchFilter,) # 将过滤器后端添加到单个视图或视图集
filterset_class = GoodsFilter
search_fields = ('name', 'goods_desc') # 搜索字段
刷新页面,输入搜索字段(模糊匹配)
![](https://img.haomeiwen.com/i5730845/e80dd7c3e4b84167.png)
这时候url为: http://127.0.0.1:8000/goods/?search=%E6%B0%B4%E6%9E%9C
可以搜索对应的内容。
也可以对一个外键或ManyToManyField
执行相关的查找,使用查找API双下划线表示法:
search_fields = ('name', 'goods_desc', 'category__name') # 最后表示搜索外键分类名称
默认情况下,搜索将使用不区分大小写的部分匹配。搜索参数可以包含多个搜索项,这些搜索项应该用空格和/或逗号分隔。如果使用多个搜索项,则仅当所提供的所有项都匹配时,才会在列表中返回对象。
搜索行为可能受到search_fields前置各种字符的限制。
-
^
:以搜索的文本开始。 -
=
:精确匹配。 -
@
:全文搜索。(目前只支持Django的MySQL后端)。 -
$
:正则表达式搜索。
使用OrderingFilter
参考: https://www.django-rest-framework.org/api-guide/filtering/#orderingfilter
OrderingFilter
类支持简单的查询参数控制的结果排序。
默认情况下,查询参数名为ordered
,但是可以通过ORDERING_PARAM
设置覆盖该参数。
修改 views.py
class GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
"""
显示商品列表,分页、过滤、搜索、排序
"""
queryset = Goods.objects.all() # 使用get_queryset函数,依赖queryset的值
serializer_class = GoodsSerializer
pagination_class = GoodsPagination
filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,) # 将过滤器后端添加到单个视图或视图集
filterset_class = GoodsFilter
search_fields = ('name', 'goods_desc', 'category__name') # 搜索字段
ordering_fields = ('click_num', 'sold_num', 'shop_price') # 排序
访问页面点击任意排序
![](https://img.haomeiwen.com/i5730845/ac17ce3b88010c07.png)
这时候url为: http://127.0.0.1:8000/goods/?ordering=shop_price
如果是倒排序,则url为: http://127.0.0.1:8000/goods/?ordering=-shop_price
当然,也可以根据过滤后的内容进行排序
![](https://img.haomeiwen.com/i5730845/b1a0672b18d93dd2.png)
网友评论