这是我使用的过滤器集的一个稍微简化的示例,我将其与 Django Rest Framework 的 DjangoFilterBackend 一起使用。我希望能够向 /api/bookmarks/?title__contains=word1&title__contains=word2
发送请求,并返回包含这两个词的结果,但目前它忽略第一个参数,只过滤词2。
如有任何帮助,我们将不胜感激!
class BookmarkFilter(django_filters.FilterSet):
class Meta:
model = Bookmark
fields = {
'title': ['startswith', 'endswith', 'contains', 'exact', 'istartswith', 'iendswith', 'icontains', 'iexact'],
}
class BookmarkViewSet(viewsets.ModelViewSet):
serializer_class = BookmarkSerializer
permission_classes = (IsAuthenticated,)
filter_backends = (DjangoFilterBackend,)
filter_class = BookmarkFilter
ordering_fields = ('title', 'date', 'modified')
ordering = '-modified'
page_size = 10
最佳答案
主要问题是您需要一个了解如何对多个值进行操作的过滤器。基本上有两种选择:
- 使用
MultipleChoiceFilter
(不推荐用于此实例) - 编写自定义过滤器类
使用MultipleChoiceFilter
class BookmarkFilter(django_filters.FilterSet):
title__contains = django_filters.MultipleChoiceFilter(
name='title',
lookup_expr='contains',
conjoined=True, # uses AND instead of OR
choices=[???],
)
class Meta:
...
虽然这保留了您想要的语法,但问题是您必须构建一个选择列表。我不确定您是否可以简化/减少可能的选择,但看起来您似乎需要从数据库中获取所有标题,将标题拆分为不同的单词,然后创建一个集合以删除重复项。根据您拥有的记录数量,这似乎会很昂贵/很慢。
自定义过滤器
或者,您可以创建自定义过滤器类 - 如下所示:
class MultiValueCharFilter(filters.BaseCSVFilter, filters.CharFilter):
def filter(self, qs, value):
# value is either a list or an 'empty' value
values = value or []
for value in values:
qs = super(MultiValueCharFilter, self).filter(qs, value)
return qs
class BookmarkFilter(django_filters.FilterSet):
title__contains = MultiValueCharFilter(name='title', lookup_expr='contains')
class Meta:
...
用法(注意值是用逗号分隔的):
GET /api/bookmarks/?title__contains=word1,word2
结果:
qs.filter(title__contains='word1').filter(title__contains='word2')
语法略有改变,但基于 CSV 的过滤器不需要构建不必要的选择集。
请注意,实际上不可能支持 ?title__contains=word1&title__contains=word2
语法,因为小部件无法呈现合适的 html 输入。您需要使用 SelectMultiple
(同样需要选择),或者在客户端使用 javascript 添加/删除具有相同 name
属性的其他文本输入。
无需赘述,过滤器和过滤器集只是 Django 表单的扩展。
- 一个
Filter
有一个表单Field
,它又有一个Widget
。 FilterSet
由Filter
组成。FilterSet
根据其过滤器的字段生成内部表单。
每个过滤器组件的职责:
- 小部件从
数据
中检索原始值QueryDict
. - 该字段验证原始值。
- 过滤器使用经过验证的值构造对查询集的
filter()
调用。
为了对同一个过滤器应用多个值,您需要一个了解如何对多个值进行操作的过滤器、字段和小部件。
自定义过滤器通过混合 BaseCSVFilter
实现这一点,后者又将“逗号分隔 => 列表”功能混合到组合字段和小部件类中。
我建议查看 CSV 混合宏的源代码,简而言之:
- widget将传入值拆分为值列表。
- field通过验证“主”字段类(例如
CharField
或IntegerField
)上的各个值来验证整个值列表。该字段还派生了混合的小部件。 - filter简单地派生混合字段类。
CSV 过滤器旨在与 in
和 range
查找一起使用,它们接受值列表。在这种情况下,contains
需要一个值。 filter()
方法通过遍历值并将各个过滤器调用链接在一起来解决此问题。
关于python - 带 DRF 的 Django 过滤器 - 在使用相同查找应用多个值时如何处理 'and'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41194200/