【问题标题】:Django find items from db by values from list?Django通过列表中的值从数据库中查找项目?
【发布时间】:2018-11-24 16:21:24
【问题描述】:

我有一个字符串列表:

phrases_filter = json.loads(request.GET['phrases_filter'])
['xx', 'yy']

我需要在 db 中查找所有包含 xx OR yy

的短语

我试过这样:

Phrase.objects.filter(name__in phrases_filter)

但这只给了我名字中包含 xx AND yy

的短语

【问题讨论】:

    标签: python django python-3.x django-queryset


    【解决方案1】:

    我们可以展开列表,并用or-logic定义一组__contains谓词:

    from django.db.models import Q
    from functools import reduce
    from operator import or_
    
    Phrase.objects.filter(
        reduce(or_, (Q(name__contains=e) for e in phrases_filter))
    )

    对于给定的phrases_filter,我们将生成等价于:

    Phrase.objects.filter(
        Q(name__contains='xx') | Q(name__contains='yy')
    )

    所以reduce(..) 将在Q(..) 对象的生成器 上运行,这里是[Q(name__contains='xx'), Q(name__contains='yy')]reduce(..) 的工作方式类似于 函数式编程 中已知的“折叠”(这是 catamorphism 的一个特例)。

    因此,我们将在两者之间添加or_s,从而得到Q(name__contains='xx') | Q(name__contains='yy')。这是一个基本上对过滤条件进行编码的对象:这意味着name 列应该__contains 子字符串'xx',或子字符串'yy'

    注意:如果你想匹配大小写敏感(所以行带有XX,或Xx,或xX,或xx所有个候选),然后将__contains替换为__<b>i</b>contains

    编辑:根据您的评论,如果phrases_filter 为空,您希望所有行都匹配,我们可以使用if 语句来做到这一点:

    from django.db.models import Q
    from functools import reduce
    from operator import or_
    
    queryset = Phrase.objects.all()
    if phrases_filter:
        queryset = filter(
            reduce(or_, (Q(name__contains=e) for e in phrases_filter))
        )

    所以只有在phrases_filter 元素上包含至少的情况下,我们才会执行过滤。

    【讨论】:

    • 你能不能逐行解释,我不太明白它是怎么工作的,这是什么意思
    • 这个phrases_filter也可以为空
    • @user2950593:如果它是空的,那会发生什么?没有匹配,还是所有行都匹配?
    • 所有行匹配=)
    • 好的,似乎正在工作=) 这是完成这项任务的首选方式吗?
    猜你喜欢
    • 1970-01-01
    • 2010-11-13
    • 1970-01-01
    • 1970-01-01
    • 2016-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多