【问题标题】:Filter Django database for field containing any value in an array过滤 Django 数据库中包含数组中任何值的字段
【发布时间】:2012-02-15 11:24:07
【问题描述】:

我有一个 django 模型和一个代表用户全名的字段。我的客户希望我设置一个过滤器,以根据字符串数组搜索用户,其中所有字符串都必须在全名中不区分大小写。

例如

如果用户full_name = "Keith, Thomson S."

我有一个列表['keith','s','thomson']

我想执行过滤器等效

Profile.objects.filter(full_name__icontains='keith',full_name__icontains='s',full_name__icontains='thomson')

问题是这个列表可以是动态大小的——所以我不知道该怎么做。

有人有什么想法吗?

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    连续调用filter,如下所示:

    queryset = Profile.objects.all()
    strings = ['keith', 's', 'thompson']
    for string in strings:
        queryset = queryset.filter(full_name__icontains=string)
    

    您也可以将& 和一堆Q 对象放在一起:

    condition = Q(full_name__icontains=s[0])
    for string in strings[1:]:
        condition &= Q(full_name__icontains=string)
    queryset = Profile.objects.filter(condition) 
    

    一种更神秘的写法,避免显式循环:

    import operator
    # ...
    condition = reduce(operator.and_, [Q(full_name__icontains=s) for s in strings])
    queryset = Profile.objects.filter(condition)
    

    【讨论】:

    • 我想知道链接所有这些过滤器后最终的 sql 表达式会是什么样子。
    • @akonsu 我刚试过(嗯,类似的东西)——它在where子句中被翻译成一系列ANDs,即full_name LIKE %keith% AND full_name LIKE %s% AND ...
    • @isbadawi, +1 - 请注意,多个 Q 对象的默认运算符是 AND,因此您可以只使用 *[Q1, Q2, Q3] 而无需使用 reduce / operator.and_。
    • @IsmailBadawi - 这也适用于主键。我有类似的问题,obj = ModelClass.objects.filter(name__contains("substr")) name is a primary key ?
    【解决方案2】:

    使用operator 函数and_or_ 组合Q() 条件列表更短

    from operator import and_, or_
    li = ['keith', 's', 'thompson']
    

    匹配所有字符串的项目 (and_)

    Profile.objects.filter(reduce(and_, [Q(full_name__icontains=q) for q in li]))
    

    匹配任何字符串的项目 (or_)

    Profile.objects.filter(reduce(or_, [Q(full_name__icontains=q) for q in li]))
    

    Q() 函数实现了__or__()__and__() 将两个Q() 对象连接在一起,因此可以使用对应的operator 函数调用它们。

    【讨论】:

      【解决方案3】:

      类似的东西:

      
      array = ['keith', 's', 'thomson']
      regex = '^.*(%s).*$' % '|'.join(array)
      Profile.objects.filter(full_name__iregex=regex)
      

      编辑:这是错误的,OP 想要同时包含所有字符串的名称。

      【讨论】:

        猜你喜欢
        • 2010-09-15
        • 1970-01-01
        • 2015-03-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-01-14
        • 1970-01-01
        • 2017-11-02
        相关资源
        最近更新 更多