如何在 Django 查询中组合 Python 的“operator.and_”和“operator.or_”?

Yax*_*Yax 1 python django

我不知道这是否可以获得,但是如何在这个 Django 查询中组合Pythonoperator.and_and ?operator.or_

我想从模型中获取包含@trending #trending不包含的文章。我们假设 loaded_listArticlesloaded_list = [3,4,2,5,7,8,3]

我这样做的一种方法是:

from django.db.models import Q
articles = Articles.objects.filter(Q(content__icontains = '@trending') | Q(content__icontains = '#trending') & ~Q(id__in = loaded_list))[:5]
Run Code Online (Sandbox Code Playgroud)

下面的代码只是为了展示我想要实现的目标,但是如何正确编写它呢?

import operator
from django.db.models import Q

query = reduce(operator.and_|or_,[(['@trending' or '#trending']), ~Q(id__in = loaded_list )])
articles = Articles.objects.filter(query)
Run Code Online (Sandbox Code Playgroud)

Pet*_*per 8

我仍然不确定您为什么要按照您所描述的方式执行此操作,但肯定可以用operator.or_and编写您给出的表达式operator.and_|与使用和&表达相同的逻辑相比,这样做不会给您带来任何好处,但它是合法的。

operator.or_和是与和运算符执行operator.and_的相同操作的功能包装。通常,在将操作作为可调用可用很有用的情况下使用它们,例如调用在编写代码时未知的序列。例如,这是一个简洁的(但完全未优化的,请不要实际使用它)正整数的阶乘函数:|&reduce

import operator
def slow_factorial(n):
    return reduce(operator.mul, xrange(1, n+1))
Run Code Online (Sandbox Code Playgroud)

您的查询的一个子句是:

Q(content__icontains = '@trending') | Q(content__icontains = '#trending')
Run Code Online (Sandbox Code Playgroud)

也可以写成:

operator.or_(Q(content__icontains = '@trending'),
             Q(content__icontains = '#trending'))
Run Code Online (Sandbox Code Playgroud)

您可以通过以下方式实现相同的最终Q目标(可能效率较低,但我还没有实际分析过):

some_q = reduce(operator.or_,
                (Q(content__icontains = '@trending'),
                 Q(content__icontains = '#trending')))
Run Code Online (Sandbox Code Playgroud)

然后该Q对象可以与另一个对象组合:

articles = Articles.objects.filter(some_q & ~Q(id__in = loaded_list))
Run Code Online (Sandbox Code Playgroud)

这与以下内容相同:

articles = Articles.objects.filter(operator.and_(some_q, ~Q(id__in = loaded_list)))
Run Code Online (Sandbox Code Playgroud)

或者,再次作为一个不太可读的表达式:

query = reduce(operator.and_,
               (some_q,
                ~Q(id__in=loaded_list)))
articles = Articles.objects.filter(query)
Run Code Online (Sandbox Code Playgroud)

或者完全明确:

query = reduce(operator.and_,
               (reduce(operator.or_,
                       (Q(content__icontains = '@trending'),
                        Q(content__icontains = '#trending'))),
                ~Q(id__in=loaded_list))
Run Code Online (Sandbox Code Playgroud)

我想我已经得到了括号,但如果我发现我平衡了它们是错误的,我不会感到震惊 - 容易犯这种错误只是与简单表达式相比这是一个较差的实现的原因之一你在问题中使用了。

如果您能更多地解释您想要做什么以及为什么需要使用名称而不是内置运算符语法,我希望能够修改这个reduce答案operator。您想要搜索的术语列表在编码时未知且长度未知吗?这是我能想到的第一个案例,reduceetc 会有所帮助。