我正在阅读动态生成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
对象。
答案 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}}方法的行为。