python测试开发django-169.过滤器django-filter 入门使用

前言

在管理后台查询的时候,经常有需要查询包含某个内容,按时间段查询,或者商品价格大于多少,小于多少各种查询条件。
django-filter 过滤器专门解决这种查询的问题。

环境准备

使用pip安装django-filter,目前安装的版本v2.2.0

pip install django-filter

在setting.py添加 django_filtersINSTALLED_APPS

INSTALLED_APPS = [
    ...

    'django_filters',
]

Django-filter 已针对所有支持的 Python 和Django版本以及最新版本的 Django REST Framework ( DRF ) 进行了测试。
python:3.5、3.6、3.7、3.8
django:2.2、3.0、3.1
DRF : 3.10+

简单入门

Django-filter 提供了一种基于用户提供的参数过滤查询集的简单方法。
假设我们有一个Product模型,我们想让我们的用户过滤他们在列表页面上看到的产品。

先设计模型

class Manufacturer(models.Model):
    name = models.CharField(max_length=255)
    city = models.CharField(max_length=255)

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    description = models.TextField()
    release_date = models.DateField()
    manufacturer = models.ForeignKey(Manufacturer,
                                     on_delete=models.CASCADE)

过滤器设置,希望让我们的用户根据名称、价格或发布日期进行过滤

  • exact 精准查找,等价于filter(name=xx),对应sql语句 where name='xx';
  • iexact 使用 like 进行查找, 对应sql语句 where name like 'xx';

过滤器类似于 Django 的 ModelForm。参考之前的https://www.cnblogs.com/yoyoketang/p/15013472.html

import django_filters

class ProductFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(lookup_expr='iexact')

    class Meta:
        model = Product
        fields = ['price', 'release_date']

以上为”价格”和”发布日期”字段生成”精确”查找。

写个视图

def product_list(request):
    f = ProductFilter(request.GET, queryset=Product.objects.all())
    return render(request, 'demo.html', {'filter': f})

template模板

<body>

    <form method="get">
        {{ filter.form.as_p }}
        <input type="submit">
    </form>
    {% for obj in filter.qs %}
        {{ obj.name }} - ${{ obj.price }}
    {% endfor %}

</body>

urls.py配置个访问地址

url(r'^product$', views.product_list)

浏览器访问

python测试开发django-169.过滤器django-filter 入门使用

不输入查询内容,默认查询全部,可以根据name/price/release_date查询

python测试开发django-169.过滤器django-filter 入门使用

该form属性包含一个普通的 Django 表单,当我们遍历 时,FilterSet.qs我们会得到结果查询集中的对象。

FilterSet.qs查询结果

FilterSet.qs 查询的结果是 QuerySet 集合,可以转成 json 格式

from django.forms.models import model_to_dict

def product_list(request):
    f = ProductFilter(request.GET, queryset=Product.objects.all())
    s = [model_to_dict(i) for i in f.qs]
    return JsonResponse({"code": 0, "msg": "success", "data": s})

查询结果

{
    "code": 0,
    "msg": "success",
    "data": [{
        "id": 1,
        "name": "\u60a0\u60a0",
        "price": "22.23",
        "description": "aa",
        "release_date": "2021-11-08",
        "manufacturer": 1
    }, {
        "id": 2,
        "name": "yy",
        "price": "101.00",
        "description": "aa",
        "release_date": "2021-11-08",
        "manufacturer": 1
    }]
}

.qs过滤

要按request对象过滤主查询集,只需覆盖该 FilterSet.qs属性。例如,您可以将博客文章过滤为仅发布的文章和登录用户拥有的文章)。

class ArticleFilter(django_filters.FilterSet):

    class Meta:
        model = Article
        fields = [...]

    @property
    def qs(self):
        parent = super().qs
        author = getattr(self.request, 'user', None)

        return parent.filter(is_published=True) \
            | parent.filter(author=author)

过滤相关查询集 ModelChoiceFilter

ModelChoiceFilter和ModelMultipleChoiceFilter 支持可调用的行为。
如果传递了一个可调用对象,它将以 request 为唯一参数进行调用 。这允许您执行相同类型的基于请求的过滤,而无需求助于覆盖 FilterSet. init.

def departments(request):
    if request is None:
        return Department.objects.none()

    company = request.user.company
    return company.department_set.all()

class EmployeeFilter(filters.FilterSet):
    department = filters.ModelChoiceFilter(queryset=departments)
    ...

自定义过滤字段 Filter.method

您可以通过指定 method 执行过滤来控制过滤器的行为。在方法参考中查看更多信息。请注意,您可以访问过滤器集的属性,例如 request.

class F(django_filters.FilterSet):
    username = CharFilter(method='my_custom_filter')

    class Meta:
        model = User
        fields = ['username']

    def my_custom_filter(self, queryset, name, value):
        return queryset.filter(**{
            name: value,
        })

声明过滤器

声明式语法在创建过滤器时为您提供了最大的灵活性,但它相当冗长。我们将使用下面的例子来勾勒核心过滤器参数上 FilterSet:

class ProductFilter(django_filters.FilterSet):
    price = django_filters.NumberFilter()
    price__gt = django_filters.NumberFilter(field_name='price', lookup_expr='gt')
    price__lt = django_filters.NumberFilter(field_name='price', lookup_expr='lt')

    release_year = django_filters.NumberFilter(field_name='release_date', lookup_expr='year')
    release_year__gt = django_filters.NumberFilter(field_name='release_date', lookup_expr='year__gt')
    release_year__lt = django_filters.NumberFilter(field_name='release_date', lookup_expr='year__lt')

    manufacturer__name = django_filters.CharFilter(lookup_expr='icontains')

    class Meta:
        model = Product

过滤器有两个主要参数:

  • field_name:要过滤的模型字段的名称。您可以使用 Django 的__语法遍历”关系路径”来过滤相关模型上的字段。例如:manufacturer__name。
  • lookup_expr:过滤时使用的字段查找。__ 可以再次使用Django 的语法来支持查找转换。例如:year__gte。

字段field_name和字段一起lookup_expr代表一个完整的 Django 查找表达式。Django 的查找参考中提供了查找表达式的详细说明。django-filter 支持包含转换和最终查找的表达式。

使用 Meta.fields 生成过滤器

FilterSet Meta 类提供了一个fields属性,可用于轻松指定多个过滤器,而无需大量代码重复。基本语法支持多个字段名称的列表:

import django_filters

class ProductFilter(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = ['price', 'release_date']

以上为”价格”和”发布日期”字段生成”精确”查找。此外,字典可用于为每个字段指定多个查找表达式:

import django_filters

class ProductFilter(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = {
            'price': ['lt', 'gt'],
            'release_date': ['exact', 'year__gt'],
        }

以上将生成 ‘price__lt’、’price__gt’、’release_date’ 和 ‘release_date__year__gt’ 过滤器。

&#x8FC7;&#x6EE4;&#x5668;&#x67E5;&#x627E;&#x7C7B;&#x578B;&#x201C;&#x7CBE;&#x786E;&#x201D;&#x662F;&#x9690;&#x5F0F;&#x9ED8;&#x8BA4;&#x503C;&#xFF0C;&#x56E0;&#x6B64;&#x6C38;&#x8FDC;&#x4E0D;&#x4F1A;&#x6DFB;&#x52A0;&#x5230;&#x8FC7;&#x6EE4;&#x5668;&#x540D;&#x79F0;&#x4E2D;&#x3002;&#x5728;&#x4E0A;&#x9762;&#x7684;&#x793A;&#x4F8B;&#x4E2D;&#xFF0C;&#x53D1;&#x5E03;&#x65E5;&#x671F;&#x7684;&#x786E;&#x5207;&#x8FC7;&#x6EE4;&#x5668;&#x662F;&#x201C;release_date&#x201D;&#xFF0C;&#x800C;&#x4E0D;&#x662F;&#x201C;release_date__exact&#x201D;&#x3002;&#x8FD9;&#x53EF;&#x4EE5;&#x88AB; FILTERS_DEFAULT_LOOKUP_EXPR &#x8BBE;&#x7F6E;&#x8986;&#x76D6;&#x3002;

类中fields序列中的项目Meta可能包括”关系路径”,使用 Django 的__语法过滤相关模型上的字段:

class ProductFilter(django_filters.FilterSet):
    class Meta:
        model = Product
        fields = ['manufacturer__country']

覆盖默认过滤器

像django.contrib.admin.ModelAdmin,它可以覆盖默认的过滤器使用相同类型的所有车型领域 filter_overrides的Meta类:

class ProductFilter(django_filters.FilterSet):

    class Meta:
        model = Product
        fields = {
            'name': ['exact'],
            'release_date': ['isnull'],
        }
        filter_overrides = {
            models.CharField: {
                'filter_class': django_filters.CharFilter,
                'extra': lambda f: {
                    'lookup_expr': 'icontains',
                },
            },
            models.BooleanField: {
                'filter_class': django_filters.BooleanFilter,
                'extra': lambda f: {
                    'widget': forms.CheckboxInput,
                },
            },
        }

更多使用参考官方文档https://django-filter.readthedocs.io/en/stable/guide/install.html

Original: https://blog.csdn.net/qq_27371025/article/details/121294614
Author: 上海-悠悠
Title: python测试开发django-169.过滤器django-filter 入门使用

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/734782/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球