理解Django Q - 动态

时间:2016-09-28 18:40:17

标签: python django list-comprehension

我正在阅读动态生成Q对象的http://localhost:56477/scripts/config-esnext.js。我理解(在大多数情况下)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对象。

1 个答案:

答案 0 :(得分:4)

该文章依赖于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'}。在super()调用中,children变量为

children = list(args) + list(kwargs.items())

评估为

children = list(()) + list(('question__contains', 'dinner'),)

简化为

children = [('question__contains', 'dinner')]

请注意,如果您使用Q(('question__contains', 'dinner')),也可以获得此结果。在这种情况下,args是元组(('question__contains', 'dinner'),)kwargs是空字典{}

super()调用中,children变量的计算结果为

children = list((('question__contains', 'dinner'),)) + list([])

简化了与之前相同的结果,

children = [('question__contains', 'dinner')]

我们已经证明Q(question__contains=dinner)等同于Q(('question__contains', 'dinner')),因此您可以通过循环列表推导中的2元组列表来生成Q()个对象的列表。 / p>

>>> 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]

这样,您就不会依赖__init__的{​​{1}}方法的行为。