美文网首页
【Vue+DRF生鲜电商】09.使用DRF的filter过滤商品

【Vue+DRF生鲜电商】09.使用DRF的filter过滤商品

作者: 吾星喵 | 来源:发表于2019-04-24 17:52 被阅读0次

欢迎访问我的博客专题

源码可访问 Github 查看

DRF过滤商品列表

GoodsListViewSet(mixins.ListModelMixin, viewsets.GenericViewSet)继承的viewsets.GenericViewSetGenericViewSet(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/

image.png

可以看到总的数量已经发生变化。

获取url的参数request.query_params,传递价格区间

参考 https://www.django-rest-framework.org/api-guide/requests/#query_params

request.query_paramsrequest.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

image.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=

image.png

但是,如果要模糊搜索,这时候url为 http://127.0.0.1:8000/goods/?name=%E6%B0%B4%E6%9E%9C&goods_desc=

image.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

image.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
image.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')  # 搜索字段

刷新页面,输入搜索字段(模糊匹配)

image.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')  # 排序

访问页面点击任意排序

image.png

这时候url为: http://127.0.0.1:8000/goods/?ordering=shop_price

如果是倒排序,则url为: http://127.0.0.1:8000/goods/?ordering=-shop_price

当然,也可以根据过滤后的内容进行排序

image.png

这时候url为: http://127.0.0.1:8000/goods/?goods_desc=&max_price=&min_price=&name=%E6%B0%B4%E6%9E%9C&ordering=-shop_price

相关文章

网友评论

      本文标题:【Vue+DRF生鲜电商】09.使用DRF的filter过滤商品

      本文链接:https://www.haomeiwen.com/subject/recngqtx.html