我正在读关于动态生成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()
方法的行为。