django-filter使用文档

Django-Filter 使用笔记


前言:Django-Filter 是一个 Django 应用,用于过滤 QuerySets。它的目的是简化过滤 QuerySets 的过程,提供一个简单的方法来定义过滤器。
它的功能类似于 Django 的 ORM 查询,但是更简单。

官网地址: https://django-filter.readthedocs.io/en/stable/

要求: 支持的 Python 版本以及最新版本的 Django REST Framework(DRF)进行了测试。


1. 安装

    pip install django-filter

然后将django-filter添加到 INSTALLED_APPS

    INSTALLED_APPS = [
        ...
        'django_filters',
    ]

2. 入门使用

2.1 模型

"""
产品库
"""

from django.db import models

class ProductModel(models.Model):
    name = models.CharField(max_length=100, blank=True, verbose_name="产品名称")
    price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="价格")
    description = models.TextField(blank=True, verbose_name="描述")
    sn = models.CharField(max_length=100, blank=True, verbose_name="产品编号")
    manufacturer = models.ForeignKey(Manufacturer, on_delete=models.PROTECT, verbose_name="生产厂家")
    created_at = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")

    class Meta:
        verbose_name = "产品"
        verbose_name_plural = "产品"
        db_table = "product"

2.2 过滤器

在产品表中,需要根据产品名称、价格、产品编号、生产厂家等字段进行过滤。

import django_filters

class ProductFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(lookup_expr='icontains')
    price = django_filters.NumberFilter()
    sn = django_filters.CharFilter(lookup_expr='icontains')
    manufacturer = django_filters.CharFilter(lookup_expr='icontains')

    class Meta:
        model = ProductModel
        fields = ['name', 'price', 'sn', 'manufacturer']

lookup_expr 是过滤器的查询表达式,icontains 表示忽略大小写的包含查询。

2.3 声明式过滤器

声明式语法在创建过滤器时为您提供了最大的灵活性,但它相当冗长。如果你只想简单地过滤字段,
那么您可以使用 FilterSet 类的 Meta.fields 属性来简化过滤器的创建。

class ProductFilter(FilterSet):  
    # 价格范围过滤  
    price_gt = NumberFilter(field_name='price', lookup_expr='gt', label='价格大于')  
    price_lt = NumberFilter(field_name='price', lookup_expr='lt', label='价格小于')  
      
    # 制造商名称模糊搜索  
    manufacturer_name = CharFilter(field_name='manufacturer__name', lookup_expr='icontains', label='制造商名称包含')  
  
    class Meta:  
        model = Product  
        fields = ['price_gt', 'price_lt', 'manufacturer_name', 'sn']  # 显式列出所有你想在表单中显示的字段 
  • /api/product/?manufacturer_name=xxxx 将会查询所有制造商名称中包含 “xxxx”(不区分大小写,因为你使用了 icontains 查找表达式)的
    Product 实例。
  • /api/product/?price_gt=10 将会查询所有价格大于 10 的 Product 实例。
  • /api/product/?manufacturer_name=xxxx&price_gt=10 将会查询所有制造商名称中包含 “xxxx” 并且价格大于 10 的 Product 实例。

2.4 Meta.fields 生成过滤器

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

import django_filters

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

根据上面的代码,django-filter 将自动创建两个过滤器,一个用于价格,一个用于发布日期。这两个过滤器将使用默认的查询表达式(exact)。
exact 是精确查找,即只有字段值与查询值完全相等时才返回结果。

为每个字段指定多个查询表达式

class ProductFilter(django_filters.FilterSet):  
    # 你可以在这里添加自定义的过滤方法或字段  
    # 但对于基本的查找,我们只需要在 Meta 类中配置  
  
    class Meta:  
        model = Product  
        fields = {  
            'price': ['lt', 'gt'],  # 允许小于和大于的价格过滤  
            'created_at': ['gt'],   # 允许大于特定创建时间的过滤  
            # 如果你还想要基于 sn 字段进行精确匹配,可以这样  
            'sn': ['exact'],  
        }  
  
        # 如果你想要为过滤器设置更友好的标签或帮助文本,可以这样做  
        # labels = {  
        #     'price': _('价格'),  
        #     'created_at': _('创建时间'),  
        #     'sn': _('编号'),  
        # }
  • /api/product/?price_gt=10&created_at_gt=2023-01-01 将会查询价格大于 10 并且创建时间大于 2023-01-01 的 Product 实例。

3.与DRF集成

3.1 配置Django全局过滤器

# settings.py
INSTALLED_APPS = [
    # ...
    'rest_framework',
    'django_filters',
]

REST_FRAMEWORK = {
    'DEFAULT_FILTER_BACKENDS': (
        'django_filters.rest_framework.DjangoFilterBackend',
        # ...
    ),
}

3.2 在视图中使用自定义过滤器类 filterset_class

from rest_framework import generics
from django_filters import rest_framework as filters
from myapp import Product


class ProductFilter(filters.FilterSet):
    min_price = filters.NumberFilter(field_name="price", lookup_expr='gte')
    max_price = filters.NumberFilter(field_name="price", lookup_expr='lte')

    class Meta:
        model = Product
        fields = ['category', 'in_stock']


class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    # filter_backends = (filters.DjangoFilterBackend,)  # 如果配置全局了,此处不需要再配置,如果没有配置3.1中的全局,需要手动在视图接口中写入此行代码
    filterset_class = ProductFilter  # 指定此视图的过滤类为 ProductFilter

上述 ProductList 接口中就可以使用 min_pricemax_price 进行价格区间过滤。

  • /api/product/?min_price=10&max_price=100 将会查询价格在 10 到 100 之间的 Product 实例。

3.3 在视图中使用自定义过滤器字段 filterset_fields

from rest_framework import generics
from django_filters import rest_framework as filters
from myapp import Product


class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    filter_backends = (filters.DjangoFilterBackend,)
    filterset_fields = ('category', 'in_stock')
    # 也可以写为
    """
    filterset_fields = {
        'category': ['exact'],
        'in_stock': ['exact'],
    }
    或者
    filterset_fields = "__all__"  # 全部字段精确查找
    """
    

4. 注意事项

在 Django REST framework 结合 django-filter 的使用中,filterset_classfilterset_fields 通常不会同时在一个视图类中直接使用,因为它们提供了不同的方式来定义过滤逻辑。然而,理解它们之间的关系和用法是很重要的。

filterset_class

filterset_class 属性允许你指定一个 FilterSet 类,这个类定义了过滤字段、方法以及可能的自定义过滤逻辑。当你需要更复杂的过滤逻辑,比如跨字段的过滤、排除特定值的过滤等,你应该使用 filterset_class

filterset_fields

filterset_fields 是一个简单的快捷方式,用于快速指定应该被过滤的模型字段。当你只需要对模型的几个字段进行基本的过滤(如精确匹配、模糊匹配等),并且不需要复杂的过滤逻辑时,filterset_fields 是一个很方便的选择。

不能同时使用?

从技术上讲,filterset_classfilterset_fields 可以在同一个视图类中设置,但通常不推荐这样做,因为这样做可能会导致意料之外的行为或冲突。filterset_class 提供了更高的灵活性和控制力,而 filterset_fields 则是为了简化常见的用例。

如果你同时设置了 filterset_classfilterset_fieldsdjango-filter 可能会优先使用 filterset_class(这取决于 django-filter 的具体实现和版本),因为 filterset_class 提供了更具体的过滤配置。然而,由于这种不明确的行为,最好避免同时使用它们。

最佳实践

  • 如果你的过滤需求很简单,只需要对几个字段进行基本的过滤,那么使用 filterset_fields 就足够了。
  • 如果你的过滤需求更复杂,比如需要跨字段的过滤、自定义过滤方法或逻辑,那么你应该定义一个 FilterSet 类,并在视图中使用 filterset_class 来指定它。

示例

使用 filterset_class 的示例:

from rest_framework import generics
from django_filters import FilterSet, CharFilter
from myapp.models import Product
from myapp.serializers import ProductSerializer

class ProductFilter(FilterSet):
    category_name = CharFilter(field_name='category__name', lookup_expr='icontains')

    class Meta:
        model = Product
        fields = ['category', 'in_stock', 'category_name']

class ProductList(generics.ListAPIView):
    queryset = Product.objects.all()
    serializer_class = ProductSerializer
    filter_backends = [filters.DjangoFilterBackend]
    filterset_class = ProductFilter

在这个例子中,我们定义了一个 ProductFilter 类,它继承自 FilterSet 并包含了一个自定义的过滤字段 category_name。然后,我们在 ProductList 视图中使用了 filterset_class 来指定这个过滤集。

Django FilterDjango 框架中的一个强大的查询工具,它允许您根据指定的条件对数据库中的数据进行筛选和过滤。您可以使用它来构建复杂的查询,从数据库中获取所需的数据。 Django Filter 提供了一个简单而灵活的语法,可以通过在模型上定义过滤器类来创建过滤器。过滤器类定义了各种字段和操作符,可以与模型的属性进行匹配,以便进行筛选。 以下是一个简单的示例,演示如何使用 Django Filter 进行查询过滤: 首先,您需要安装 Django Filter 库: ``` pip install django-filter ``` 然后,在您的 Django 项目中,创建一个过滤器类,并指定要过滤的模型以及要过滤的字段: ```python import django_filters from .models import YourModel class YourModelFilter(django_filters.FilterSet): # 定义要过滤的字段以及对应的操作符 field_name = django_filters.FieldType(field_lookup='exact') class Meta: model = YourModel fields = ['field_name'] ``` 接下来,在您的视图中使用该过滤器类来进行数据过滤: ```python from django.shortcuts import render from django_filters.views import FilterView from .models import YourModel from .filters import YourModelFilter def your_view(request): # 获取 GET 请求中的过滤参数 filter_params = request.GET.copy() # 创建过滤器实例并传入过滤参数 filter = YourModelFilter(filter_params, queryset=YourModel.objects.all()) # 使用过滤器的 `qs` 属性获取过滤后的结果集 filtered_queryset = filter.qs return render(request, 'your_template.html', {'filtered_queryset': filtered_queryset}) ``` 在模板文件 `your_template.html` 中,您可以使用 `filtered_queryset` 变量来访问过滤后的结果集。 这只是一个简单的示例,Django Filter 还提供了许多其他功能和选项,例如范围查询、多字段查询、日期查询等。您可以查阅 Django Filter 的官方文档以获取更多详细信息和示例:https://django***
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

.@d

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值