前言在管理后台查询的时候,经常有需要查询包含某个内容,按时间段查询,或者商品价格大于多少,小于多少各种查询条件。 django-filter 过滤器专门解决这种查询的问题。 环境准备使用pip安装django-filter,目前安装的版本v2.2.0 pip install django-filter 在setting.py添加django_filters 到 INSTALLED_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 }}<br /> {% endfor %}
</body> urls.py配置个访问地址 url(r'^product$', views.product_list) 浏览器访问
不输入查询内容,默认查询全部,可以根据name/price/release_date查询 该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) 过滤相关查询集 ModelChoiceFilterModelChoiceFilter和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和字段一起 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 过滤器。 过滤器查找类型“精确”是隐式默认值,因此永远不会添加到过滤器名称中。在上面的示例中,发布日期的确切过滤器是`release_date`,而不是`release_date__exact`。这可以被 FILTERS_DEFAULT_LOOKUP_EXPR 设置覆盖。 类中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./en/stable/guide/install.html
|