rest framework api

Drf-过滤,搜索,排序

2018-06-25  本文已影响12人  dyq666

目录

  1. 手动过滤

0. 概述

将这三个看似不相同的功能放到一篇文章的原因是,这三种方法的实质都是通过GETparams来对queryset进行筛选。在drf中也是这么设计的,这三个模块通常在一起处理。

Drf提供了很多种view的使用,在本文中要求使用的最低级的view是generics.GenericAPIView

通过源码查看这两者的区别。


从源码中可以看到get_queryset这个实例方法,当声明了queryset这个变量时就返回这个值。
也就是说指定了变量queryset后返回的查询集就固定了,当我们需要根据不同的情况返回查询集时,就需要overrideget_queryset方法。

在Drf中会将?xx=xxx这类的params存入self.query_params
下面是一次GET请求中,从Pycharm的Debug模式下截取的参数。(本次请求中url是以?price_min=20结尾的)

1. 手动过滤

这里完成的功能是:获取大于等于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()
  1. 可能是版本问题(这里我的drf版本是3.82),如果不设置queryset就会报错(所以这里我们将queryset随便设置为一个QuerySet)。
  2. overrideget_queryset方法。
  3. 获取query_params中的过滤条件price_min
  4. 如果有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

INSTALLED_APPS = [
    'django_filters',
]
REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': ('django_filters.rest_framework.DjangoFilterBackend',),
}

配置过滤的后端和过滤的属性。

filter_backends = (DjangoFilterBackend, )
filter_fields = ('shop_price',)

可以直接在url增加后缀?shop_price=xx

3. 进阶使用(filter_class)

django-filter文档

通常先在对应的应用目录下创建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']
  1. 继承类(一定要继承Drf中的类django_filters.rest_framework.FilterSet,不要继承django_filters.FilterSet
  2. 设置过滤条件,过滤条件中有两个重要的参数:
    1. name 代表Model中的字段
    2. lookup_expr而是djangoORM查询提供的查询方法(gt等于model.objects.filter(xx__gt=xx))。
from .filters import GoodsFilter

class xxView(xxxView):
    filter_class = GoodsFilter
  1. 常用的lookup_expr
  1. 查询外键的属性
    外键名__外键属性

  2. 使用方法进行过滤
    指定参数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类似。

在filter_backends中加入搜索功能。

filter_backends= (DjangoFilterBackend, filters.SearchFilter)

指明查询的字段即可。

search_fields = ('name',)

提供了下面几种正则化的查询方式。


比如准确查询就用=name

xxx/?search=xx

5. 排序

基本与搜索相同!

filter_backends = (DjangoFilterBackend, filters.OrderingFilter)
ordering_fields = ('name',)

xxx/?ordering=xx

上一篇 下一篇

猜你喜欢

热点阅读