我正在读关于动态生成Q对象的this article。我理解(大多数情况下)Q对象,但我不理解作者具体是如何做这个示例的:

# string representation of our queries
>>> predicates = [('question__contains', 'dinner'), ('question__contains', 'meal')]

# create the list of Q objects and run the queries as above..
>>> q_list = [Q(x) for x in predicates]

>>> Poll.objects.filter(reduce(operator.or_, q_list))
[<Poll: what shall I make for dinner>, <Poll: what is your favourite meal?>]

我特别没有得到的是列表理解。Q对象使用任意关键字参数格式化,例如Q(question__contains='dinner')
如果像作者建议的那样使用列表理解,那么在每次迭代中在Q对象中放置一个元组不是很有效吗?就像这样:Q(('question__contains', 'dinner'))
我不确定这段代码如何生成一个格式正确的Q对象。

最佳答案

本文依赖于Q()接受args和kwargs的未记录特性。
如果您查看source code for the Q class,可以看到它在__init__方法中执行以下操作。

class Q(tree.Node):
    ...
    def __init__(self, *args, **kwargs):
        super(Q, self).__init__(children=list(args) + list(kwargs.items()))

如果调用Q(question__contains=dinner)args在空元组中,()是字典。在kwargs调用中,{'question__contains': 'dinner'}变量是
children = list(args) + list(kwargs.items())

评估结果为
children = list(()) + list(('question__contains', 'dinner'),)

简化为
children = [('question__contains', 'dinner')]

请注意,如果使用super(),也可以获得此结果。在本例中,children是一个元组Q(('question__contains', 'dinner'))args是一个空字典(('question__contains', 'dinner'),)
kwargs调用中,{}变量的计算结果为
children = list((('question__contains', 'dinner'),)) + list([])

简化成和以前一样的结果,
children = [('question__contains', 'dinner')]

我们已经证明super()等同于children,因此您可以通过在列表理解中的2元组列表上循环来生成Q(question__contains=dinner)对象的列表。
>>> predicates = [('question__contains', 'dinner'), ('question__contains', 'meal')]
>>> q_list = [Q(x) for x in predicates]

就我个人而言,我可能更喜欢写信
>>> predicates = [{'question__contains': 'dinner'},  {'question__contains': 'meal'}]
>>> q_list = [Q(**kwargs) for kwargs in predicates]

这样,您就不依赖于Q(('question__contains', 'dinner'))Q()方法的行为。

08-17 12:19