为Django REST Framework提供更好的过滤功能
项目描述
django-rest-framework-filters 是Django REST framework和Django filter的扩展,它使得跨关系过滤变得容易。历史上,此扩展还提供了一些额外的功能和修复,但它们已被合并回 django-filter,因此功能数量有所减少。
使用 django-rest-framework-filters,我们可以轻松完成如下操作
/api/article?author__first_name__icontains=john /api/article?is_published!=true
功能
跨关系的简单过滤
支持跨关系的方法过滤
使用简单的param!=value语法自动否定过滤
后端缓存以提高性能
要求
Python: 2.7或3.3+
Django: 1.8, 1.9, 1.10, 1.11
DRF: 3.5, 3.6
安装
$ pip install djangorestframework-filters
用法
从django-filter升级到django-rest-framework-filters很简单
从rest_framework_filters导入而不是从django_filters导入
使用rest_framework_filters后端而不是django_filter提供的一个后端。
# django-filter
from django_filters.rest_framework import FilterSet, filters
class ProductFilter(FilterSet):
manufacturer = filters.ModelChoiceFilter(queryset=Manufacturer.objects.all())
...
# django-rest-framework-filters
import rest_framework_filters as filters
class ProductFilter(filters.FilterSet):
manufacturer = filters.ModelChoiceFilter(queryset=Manufacturer.objects.all())
...
要使用django-rest-framework-filters后端,请在您的设置中添加以下内容
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': (
'rest_framework_filters.backends.DjangoFilterBackend', ...
),
...
配置完成后,您可以使用在django-filter中找到的所有过滤器。
跨关系过滤
在过滤时,您可以使用RelatedFilter轻松遍历多个关系
from rest_framework import viewsets
import rest_framework_filters as filters
class ManagerFilter(filters.FilterSet):
class Meta:
model = Manager
fields = {'name': ['exact', 'in', 'startswith']}
class DepartmentFilter(filters.FilterSet):
manager = filters.RelatedFilter(ManagerFilter, name='manager', queryset=Manager.objects.all())
class Meta:
model = Department
fields = {'name': ['exact', 'in', 'startswith']}
class CompanyFilter(filters.FilterSet):
department = filters.RelatedFilter(DepartmentFilter, name='department', queryset=Department.objects.all())
class Meta:
model = Company
fields = {'name': ['exact', 'in', 'startswith']}
# company viewset
class CompanyView(viewsets.ModelViewSet):
filter_class = CompanyFilter
...
示例过滤调用
/api/companies?department__name=Accounting
/api/companies?department__manager__name__startswith=Bob
queryset可调用对象
由于RelatedFilter是ModelChoiceFilter的子类,因此queryset参数支持可调用行为。在以下示例中,部门集合被限制为用户的公司的那些部门。
def departments(request):
company = request.user.company
return company.department_set.all()
class EmployeeFilter(filters.FilterSet):
department = filters.RelatedFilter(filterset=DepartmentFilter, queryset=departments)
...
递归关系
也支持递归关系。可能需要指定完整的模块路径。
class PersonFilter(filters.FilterSet):
name = filters.AllLookupsFilter(name='name')
best_friend = filters.RelatedFilter('people.views.PersonFilter', name='best_friend', queryset=Person.objects.all())
class Meta:
model = Person
支持 Filter.method
django_filters.MethodFilter已被弃用,并作为所有过滤器类的method参数重新实现。它包含了旧rest_framework_filters.MethodFilter的一些实现细节,但需要更少的样板代码,并且更容易编写。
不再需要执行空/空值检查。
您可以使用任何过滤器类(CharFilter、BooleanFilter等),它将为您验证输入值。
参数签名已从(name, qs, value)更改为(qs, name, value)。
class PostFilter(filters.FilterSet):
# Note the use of BooleanFilter, the original model field's name, and the method argument.
is_published = filters.BooleanFilter(name='date_published', method='filter_is_published')
class Meta:
model = Post
fields = ['title', 'content']
def filter_is_published(self, qs, name, value):
"""
`is_published` is based on the `date_published` model field.
If the publishing date is null, then the post is not published.
"""
# incoming value is normalized as a boolean by BooleanFilter
isnull = not value
lookup_expr = LOOKUP_SEP.join([name, 'isnull'])
return qs.filter(**{lookup_expr: isnull})
class AuthorFilter(filters.FilterSet):
posts = filters.RelatedFilter('PostFilter', queryset=Post.objects.all())
class Meta:
model = Author
fields = ['name']
以上将启用以下过滤调用
/api/posts?is_published=true
/api/authors?posts__is_published=true
在第一个API调用中,过滤方法接收帖子查询集。在第二个中,它接收用户查询集。示例中的过滤方法修改了查找名称以跨关系工作,允许您查找已发布的帖子或已发布帖子的作者。
自动过滤否定/排除
FilterSets支持使用简单的param!=value语法进行自动排除。此语法内部将过滤器上的exclude属性设置为。
/api/page?title!=The%20Park
此语法支持常规过滤与排除过滤的组合。例如,以下将搜索标题中包含“Hello”的所有文章,同时排除包含“World”的文章。
/api/articles?title__contains=Hello&title__contains!=World
请注意,大多数过滤器只接受单个查询参数。在上面的例子中,title__contains和title__contains!被解释为两个不同的查询参数。以下可能无效,尽管这取决于单个过滤器类的具体细节
/api/articles?title__contains=Hello&title__contains!=World&title_contains!=Friend
允许字段上的任何查找类型
如果您需要为字段启用多个查找,django-filter为Meta.fields提供dict语法。
class ProductFilter(filters.FilterSet):
class Meta:
model = Product
fields = {
'price': ['exact', 'lt', 'gt', ...],
}
django-rest-framework-filters 允许您为任何字段启用所有可能的查找。这可以通过使用 AllLookupsFilter 或在 Meta.fields 字典式语法中使用 '__all__' 值来实现。生成的过滤器(Meta.fields,AllLookupsFilter)永远不会覆盖您声明的过滤器。
请注意,使用所有查找与在 django 表单中启用 '__all__' 字段具有相同的警告(文档)。暴露所有查找可能会允许用户构建意外泄露数据的查询。请负责任地使用此功能。
class ProductFilter(filters.FilterSet):
# Not overridden by `__all__`
price__gt = filters.NumberFilter(name='price', lookup_expr='gt', label='Minimum price')
class Meta:
model = Product
fields = {
'price': '__all__',
}
# or
class ProductFilter(filters.FilterSet):
price = filters.AllLookupsFilter()
# Not overridden by `AllLookupsFilter`
price__gt = filters.NumberFilter(name='price', lookup_expr='gt', label='Minimum price')
class Meta:
model = Product
您不能将 AllLookupsFilter 与 RelatedFilter 结合使用,因为过滤器名称将冲突。
class ProductFilter(filters.FilterSet):
manufacturer = filters.RelatedFilter('ManufacturerFilter', queryset=Manufacturer.objects.all())
manufacturer = filters.AllLookupsFilter()
为了解决这个问题,您有以下选项
class ProductFilter(filters.FilterSet):
manufacturer = filters.RelatedFilter('ManufacturerFilter', queryset=Manufacturer.objects.all())
class Meta:
model = Product
fields = {
'manufacturer': '__all__',
}
# or
class ProductFilter(filters.FilterSet):
manufacturer = filters.RelatedFilter('ManufacturerFilter', queryset=Manufacturer.objects.all(), lookups='__all__') # `lookups` also accepts a list
class Meta:
model = Product
我可以混合使用 django-filter 和 django-rest-framework-filters 吗?
是的,您可以。 django-rest-framework-filters 仅仅是 django-filter 的扩展。请注意,RelatedFilter 和其他 django-rest-framework-filters 功能是为与 rest_framework_filters.FilterSet 一起使用而设计的,不会在 django_filters.FilterSet 上运行。然而,目标 RelatedFilter.filterset 可能指向来自任一包的 FilterSet,并且这两个 FilterSet 实现都与对方的 DRF 后端兼容。
# valid
class VanillaFilter(django_filters.FilterSet):
...
class DRFFilter(rest_framework_filters.FilterSet):
vanilla = rest_framework_filters.RelatedFilter(filterset=VanillaFilter, queryset=...)
# invalid
class DRFFilter(rest_framework_filters.FilterSet):
...
class VanillaFilter(django_filters.FilterSet):
drf = rest_framework_filters.RelatedFilter(filterset=DRFFilter, queryset=...)
注意事项 & 限制
MultiWidget 不兼容
djangorestframework-filters 与解析查询名称与过滤器属性名称不同的表单小部件不兼容。尽管这仅实际适用于 MultiWidget,但它是一个影响具有此行为的自定义小部件的一般限制。受影响的过滤器包括 RangeFilter,DateTimeFromToRangeFilter,DateFromToRangeFilter,TimeRangeFilter 和 NumericRangeFilter。
为了展示这种不兼容性,考虑以下过滤器集
class PostFilter(FilterSet):
publish_date = filters.DateFromToRangeFilter()
上述过滤器允许用户对出版日期执行 range 查询。过滤器类内部使用 MultiWidget 来分别解析上界和下界值。不兼容之处在于 MultiWidget 将索引追加到其内部小部件名称。它期望解析 publish_date 而不是 publish_date_0 和 publish_date_1。可以通过在查询字符串中包含属性名称来修复此问题,尽管不推荐这样做。
?publish_date_0=2016-01-01&publish_date_1=2016-02-01&publish_date=
MultiWidget 也被不推荐使用,因为
core-api 字段自省失败出于类似原因
_0 和 _1 比不友好的 _min 和 _max
建议的解决方案是
为每个子小部件创建单独的过滤器(例如 publish_date_min 和 publish_date_max)。
使用基于 CSV 的过滤器,例如从 BaseCSVFilter/BaseInFilter/BaseRangeFilter 衍生出的过滤器。例如,
?publish_date__range=2016-01-01,2016-02-01
迁移到1.0版本
get_filters()已重命名为expand_filters()
django-filter 为其 API 添加了一个 get_filters() 类方法,因此该方法已被重命名。
发布
$ pip install -U twine setuptools wheel
$ rm -rf dist/ build/
$ python setup.py sdist bdist_wheel
$ twine upload dist/*
许可
版权所有(c)2013-2015菲利普·纽斯特罗姆 <philipn@gmail.com>,2016-2017瑞安·P·基尔比 <rpkilby@ncsu.edu>
特此授予任何人免费获得本软件及其相关文档文件(以下简称“软件”)的副本的权利,可以在不受限制的情况下处理软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件副本,并允许向软件提供副本的个人这样做,但必须遵守以下条件
上述版权声明和本许可声明应包含在软件的所有副本或实质性部分中。
软件按“原样”提供,不提供任何形式的保证,无论是明示的还是隐含的,包括但不限于适销性、适用于特定目的和未经授权的保证。在任何情况下,作者或版权所有者不对任何索赔、损害或其他责任承担责任,无论是因为合同、侵权或其他原因而引起的,无论是在软件或软件的使用或其他情况下。
项目详情
djangorestframework-filters-0.11.1.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | f9249bd6440574ff8788a8994407bf5974e461fbcf65c0bd4785f9e71836768a |
|
MD5 | 2ff2ec982010e6b29169736b53f20e14 |
|
BLAKE2b-256 | c5e7e94c0834cc345b160d51bc57e6145c4903ce0d08db0cdd3d44fa43cc2059 |
djangorestframework-filters-0.11.1-py2.py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | a7683bfbeb4eb2a246fbba830f80062fcff9697101ca87a8b7327346284aa518 |
|
MD5 | 937b458fc5436509daec518c0125fa5a |
|
BLAKE2b-256 | c0203506c608b3ec79a67c24b70702322ac46bc73e6217a0d9239dfef83e20c6 |