<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Furry Brains &#187; queryset</title>
	<atom:link href="http://furrybrains.com/tag/queryset/feed/" rel="self" type="application/rss+xml" />
	<link>http://furrybrains.com</link>
	<description>The Furry Brains blog tackles a wide range of issues related to web development and design.</description>
	<lastBuildDate>Mon, 22 Jun 2009 16:39:24 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.1</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Using &#8220;in&#8221; in QuerySets in Django</title>
		<link>http://furrybrains.com/2008/10/23/using-in-in-querysets-in-django/</link>
		<comments>http://furrybrains.com/2008/10/23/using-in-in-querysets-in-django/#comments</comments>
		<pubDate>Fri, 24 Oct 2008 03:11:14 +0000</pubDate>
		<dc:creator>Jim Dalton</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[queryset]]></category>

		<guid isPermaLink="false">http://furrybrains.com/?p=85</guid>
		<description><![CDATA[So the purpose of this post is just to look at a neat way of solving a problem in Django, and explain its mechanics and how it was put together.
In today&#8217;s example, the goal was pretty straightforward. We have a model class, Topic, that has a one-to-many relationship to a ThreadedComment model class. Each ThreadedComment [...]]]></description>
			<content:encoded><![CDATA[<p>So the purpose of this post is just to look at a neat way of solving a problem in Django, and explain its mechanics and how it was put together.</p>
<p>In today&#8217;s example, the goal was pretty straightforward. We have a model class, <code>Topic</code>, that has a one-to-many relationship to a <code>ThreadedComment</code> model class. Each <code>ThreadedComment</code> for each <code>Topic</code>, has a <code>User</code> associated with it; furthermore the <code>Topic</code> itself as a <code>User</code> associated with it (the creator of the topic).</p>
<p><span id="more-85"></span></p>
<p>The issue here is that it&#8217;s not actually a straightforward relationship between <code>Topic</code> and <code>ThreadedComment</code>, due to some complicating factors beyond the scope of this discussion. Suffice it to say what we&#8217;re looking for is a list of users who are participants in the discussion, inclusive of the topic creator. But we&#8217;re not looking for just any old list &#8212; what we need is a QuerySet, for the reason that we are making use of some specialized tags in our templates that require data to be in a QuerySet.</p>
<p>Here&#8217;s a quick example of what we want the interface to look like in the template:</p>
<pre class="brush: xml;">
	&lt;ul&gt;
	{% for participant in topic.participants %}
		&lt;li&gt;{{ participant.name }}&lt;/li&gt;
	{% endfor %}
	&lt;/ul&gt;
</pre>
<p>So let&#8217;s do this step by step.</p>
<p>First, let&#8217;s get a list of the <code>ThreadedComment</code> objects we need:</p>
<pre class="brush: python;">
ThreadedComment.public.all_for_object(topic))
</pre>
<p>The <code>all_for_object()</code> method is one of the &#8220;complications&#8221; we were referring to above. All we care about is that it returns a set of <code>ThreadedComment</code> objects for a given topic.</p>
<p>Okay, but now that we have this set of objects, how are we going to return a QuerySet that yields us User objects?</p>
<p>My co-worker actually showed this to me, so I&#8217;ll share it here. We&#8217;ll use <code>in</code> keyword argument in <code>filter()</code>, which maps to the SQL <code>IN</code> clause. The Django documentation has a simple example:</p>
<pre class="brush: python;">
Entry.objects.filter(id__in=[1, 3, 4])
</pre>
<p>is equivalent to:</p>
<pre class="brush: sql;">
SELECT ... WHERE id IN (1, 3, 4)
</pre>
<p>So that&#8217;s just what we&#8217;re going to do: pass a list of user ids as an <code>in</code> keyword argument to identify the users we want.</p>
<p>First, let&#8217;s extend our original QuerySet to get the values we need as a list:</p>
<pre class="brush: python;">
ThreadedComment.public.all_for_object(self).values_list('user_id', flat=True)
</pre>
<p>One thing is missing &mdash; we need to include the user id of the topic creator, as I mentioned above. We&#8217;ll just evaluate the QuerySet to a list and then add the topic creator to it:</p>
<pre class="brush: python;">
list(ThreadedComment.public.all_for_object(self).values_list('user_id', flat=True)) + [self.creator.id]
</pre>
<p>Now let&#8217;s take the list of ids and pass it to a QuerySet that we&#8217;ll return <code>User</code> objects. Our list goes in the <code>pk__in</code> keyword argument:</p>
<pre class="brush: python;">
User.objects.filter(
    pk__in=list(
        list(ThreadedComment.public.all_for_object(self).values_list('user_id', flat=True)) + [self.creator.id]
    )
)
</pre>
<p>Now let&#8217;s add this as a method <code>participants()</code> to the <code>Topic</code> model and throw a <code>@property</code> decorator on it so we can call it as an attribute:</p>
<pre class="brush: python;">
@property
def participants(self):
    return User.objects.filter(
        pk__in=list(
            list(ThreadedComment.public.all_for_object(self).values_list('user_id', flat=True)) + [self.creator.id]
        )
    )
</pre>
<p>And that&#8217;s all there is to it.</p>
<p>What I love about this approach is that it&#8217;s a pattern that fits in to so many places (so many that I almost feel like it deserves a higher level abstraction within the QuerySet API). There are variations that make it slightly more efficient as well; for example, if I didn&#8217;t need to append the topic creator id in my example, then I could have passed the list of ids as a query as opposed to evaluating it:</p>
<pre class="brush: python;">
User.objects.filter(
    pk__in=ThreadedComment.public.all_for_object(self).values_list('user_id', flat=True)).query
)
</pre>
<p>The advantage here is that this is evaluated as a subselect statement, so it only requires a single database call.</p>
<p>Anyhow, this technique is really fantastic when you have a set of related objects that for whatever reason you aren&#8217;t able to easily obtain as a QuerySet. Enjoy.</p>
]]></content:encoded>
			<wfw:commentRss>http://furrybrains.com/2008/10/23/using-in-in-querysets-in-django/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
