python - 带 DRF 的 Django 过滤器 - 在使用相同查找应用多个值时如何处理 'and'?

标签 python django django-rest-framework django-filter django-filters

这是我使用的过滤器集的一个稍微简化的示例,我将其与 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
  • FilterSetFilter 组成。
  • FilterSet 根据其过滤器的字段生成内部表单。

每个过滤器组件的职责:

  • 小部件从数据 中检索原始值QueryDict .
  • 该字段验证原始值。
  • 过滤器使用经过验证的值构造对查询集的 filter() 调用。

为了对同一个过滤器应用多个值,您需要一个了解如何对多个值进行操作的过滤器、字段和小部件。


自定义过滤器通过混合 BaseCSVFilter 实现这一点,后者又将“逗号分隔 => 列表”功能混合到组合字段和小部件类中。

我建议查看 CSV 混合宏的源代码,简而言之:

  • widget将传入值拆分为值列表。
  • field通过验证“主”字段类(例如 CharFieldIntegerField)上的各个值来验证整个值列表。该字段还派生了混合的小部件。
  • filter简单地派生混合字段类。

CSV 过滤器旨在与 inrange 查找一起使用,它们接受值列表。在这种情况下,contains 需要一个值。 filter() 方法通过遍历值并将各个过滤器调用链接在一起来解决此问题。

关于python - 带 DRF 的 Django 过滤器 - 在使用相同查找应用多个值时如何处理 'and'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41194200/

相关文章:

python - 对 ParamSpec 变量应用转换?

django - 使用 Django 和 AngularJs 在 Mongodb 中上传 Pdf 文件

javascript - 如何将 getAccessToken 与 fetch 功能集成,以将数据从 DRF 后端加载到 React 前端?

python - 在 Python 2.6+ 中使用 super(...) 时如何避免样板代码?

python - 从 python 中的 mysql 查询结果中删除字符

python - 根据两列的值删除 numpy 数组的行

django - PWA 无法使用 Service Worker 与 Django 一起正常工作

database - 操作错误 : FATAL: password authentication failed for user "UserName"

Django Rest框架自定义POST权限

带有 ImageFIeld 和 HTTPS 的 Django ModelSerializer