Understanding Django Q - Dynamic
<p>I'm reading <a href="http://www.michelepasin.org/blog/2010/07/20/the-power-of-djangos-q-objects/" rel="nofollow">this article</a> on dynamically generating Q objects. I understand (for the most part) Q objects but I'm not understanding how the author specifically is doing this example:</p>

<pre><code># string representation of our queries
&gt;&gt;&gt; predicates = [('question__contains', 'dinner'), ('question__contains', 'meal')]

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

&gt;&gt;&gt; Poll.objects.filter(reduce(operator.or_, q_list))
[&lt;Poll: what shall I make for dinner&gt;, &lt;Poll: what is your favourite meal?&gt;]
</code></pre>

<p>What I specifically don't get is the list comprehension. A <code>Q</code> object is formatted with arbitrary keywords arguments as such <code>Q(question__contains='dinner')</code>. </p>

<p>If doing it like the author suggests with the list comprehension, won't that effectively just place a tuple inside a <code>Q</code> object on each iteration? Like such: <code>Q(('question__contains', 'dinner'))</code>. </p>

<p>I'm not sure how this code produces a correctly formatted <code>Q</code> object. </p>

<p>The article relies on the undocumented feature that <code>Q()</code> accepts args as well as kwargs.</p>

<p>If you look at <a href="https://github.com/django/django/blob/9c522d2ed8e752932bfff62d6e2940e56dee700b/django/db/models/query_utils.py#L53" rel="nofollow">source code for the <code>Q</code> class</a>, you can see that it does the following in the <code>__init__</code> method.</p>

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

<p>If you call <code>Q(question__contains=dinner)</code> then <code>args</code> in an empty tuple <code>()</code> and <code>kwargs</code> is a dictionary <code>{'question__contains': 'dinner'}</code>. In the <code>super()</code> call, the <code>children</code> variable is</p>

<pre><code>children = list(args) + list(kwargs.items())
</code></pre>

<p>which evaluates to</p>

<pre><code>children = list(()) + list(('question__contains', 'dinner'),)
</code></pre>

<p>which simplifies to</p>

<pre><code>children = [('question__contains', 'dinner')]
</code></pre>

<p>Note that you could also get this result if you use <code>Q(('question__contains', 'dinner'))</code>. In this case, <code>args</code> is a tuple <code>(('question__contains', 'dinner'),)</code> and <code>kwargs</code> is an empty dictionary <code>{}</code>.</p>

<p>In the <code>super()</code> call, the <code>children</code> variable evaluates to</p>

<pre><code>children = list((('question__contains', 'dinner'),)) + list([])
</code></pre>

<p>which simplifies to the same result as before,</p>

<pre><code>children = [('question__contains', 'dinner')]
</code></pre>

<p>We have shown that <code>Q(question__contains=dinner)</code> is equivalent to <code>Q(('question__contains', 'dinner'))</code>, and therefore you can generate the list of <code>Q()</code> objects by looping over a list of 2-tuples in a list comprehension.</p>

<pre><code>&gt;&gt;&gt; predicates = [('question__contains', 'dinner'), ('question__contains', 'meal')]
&gt;&gt;&gt; q_list = [Q(x) for x in predicates]
</code></pre>

<p>Personally, I might prefer to write</p>

<pre><code>&gt;&gt;&gt; predicates = [{'question__contains': 'dinner'},  {'question__contains': 'meal'}]
&gt;&gt;&gt; q_list = [Q(**kwargs) for kwargs in predicates]
</code></pre>

<p>This way, you are not relying on the behaviour of the <code>__init__</code> method of the <code>Q</code>.</p>

python django list-comprehension