<?xml version="1.0" encoding="utf-8"?>
<feed xml:lang="en-us" xmlns="http://www.w3.org/2005/Atom"><title>Simon Willison's Weblog: chaining</title><link href="http://simonwillison.net/" rel="alternate"/><link href="http://simonwillison.net/tags/chaining.atom" rel="self"/><id>http://simonwillison.net/</id><updated>2008-05-01T12:31:17+00:00</updated><author><name>Simon Willison</name></author><entry><title>jQuery style chaining with the Django ORM</title><link href="https://simonwillison.net/2008/May/1/orm/#atom-tag" rel="alternate"/><published>2008-05-01T12:31:17+00:00</published><updated>2008-05-01T12:31:17+00:00</updated><id>https://simonwillison.net/2008/May/1/orm/#atom-tag</id><summary type="html">
    &lt;p&gt;Django's ORM is, in my opinion, the unsung gem of the framework. For the subset of SQL that's used in most web applications it's very hard to beat. It's a beautiful piece of API design, and I tip my hat to the people who designed and built it.&lt;/p&gt;

&lt;h4&gt;Lazy evaluation&lt;/h4&gt;

&lt;p&gt;If you haven't spent much time with the ORM, two key features are lazy evaluation and chaining. Consider the following statement:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;entries = Entry.objects.all()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Assuming you have created an Entry model of some sort, the above statement will create a Django QuerySet object representing all of the entries in the database. It will &lt;em&gt;not&lt;/em&gt; result in the execution of any SQL - QuerySets are lazily evaluated, and are only executed at the last possible moment. The most common situation in which SQL will be executed is when the object is used for iteration:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;for entry in entries:
    print entry.title&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This usually happens in a template:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;&amp;lt;ul&amp;gt;
{% for entry in entries %}
  &amp;lt;li&amp;gt;{{ entry.title }}&amp;lt;/li&amp;gt;
{% endfor %}
&amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Lazy evaluation works nicely with  &lt;a href="http://www.djangoproject.com/documentation/cache/#template-fragment-caching"&gt;template fragment caching&lt;/a&gt; - even if you pass a QuerySet to a template it won't be executed if the fragment it is used in can be served from the cache.&lt;/p&gt;

&lt;p&gt;You can modify QuerySets as many times as you like before they are executed:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;entries = Entry.objects.all()
today = datetime.date.today()
entries_this_year = entries.filter(
    posted__year = today.year
)
entries_last_year = entries.filter(
    posted__year = today.year - 1
)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Again, no SQL has been executed, but we now have two QuerySets which, when iterated, will produce the desired result.&lt;/p&gt;

&lt;h4&gt;Chaining&lt;/h4&gt;

&lt;p&gt;Chaining comes in when you want to apply multiple modifications to a QuerySet. Here are blog entries from 2006 that weren't posted in January:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;Entry.objects.filter(
    posted__year = 2006
).exclude(posted__month = 1)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And here's entries from that year posted to the category named "Personal", ordered by title:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;Entry.objects.filter(
    posted__year = 2006
).filter(
    category__name = "Personal"
).order_by('title')&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above can also be expressed like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;Entry.objects.filter(
    posted__year = 2006,
    category__name = "Personal"
).order_by('title')&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Chaining in jQuery&lt;/h4&gt;

&lt;p&gt;The parallels to &lt;a href="http://jquery.com/"&gt;jQuery&lt;/a&gt; are pretty clear. The jQuery API is built around chaining, and the jQuery &lt;a href="http://docs.jquery.com/Effects"&gt;animation library&lt;/a&gt; even uses a form of lazy evaluation to automatically queue up effects to run in sequence:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;jQuery('div#message').addClass(
	'borderfade'
).animate({
   'borderWidth': '+10px'
}, 1000).fadeOut();&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;One of the neatest things about jQuery is the plugin model, which takes advantage of JavaScript's prototype inheritance and makes it trivially easy to add new chainable methods. If we wanted to package the above dumb effect up as a plugin, we could do so like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;jQuery.fn.dumbBorderFade = function() {
    return this.addClass(
        'borderfade'
    ).animate({
       'borderWidth': '+10px'
    }, 1000).fadeOut();
};&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now we can apply it to an element like so:&lt;/p&gt;

&lt;pre&gt;&lt;code class="javascript"&gt;jQuery('div#message').dumbBorderFade();&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Custom QuerySet methods in Django&lt;/h4&gt;

&lt;p&gt;Django supports adding custom methods for accessing the ORM through the ability to implement a custom &lt;a href="http://www.djangoproject.com/documentation/model-api/#managers"&gt;Manager&lt;/a&gt;. In the above examples, &lt;code class="python"&gt;Entry.objects&lt;/code&gt; is the Manager. The downside of this approach is that methods added to a manager can only be used at the beginning of the chain.&lt;/p&gt;

&lt;p&gt;Luckily, Managers also provide a hook for returning a custom QuerySet. This means we can create our own QuerySet subclass and add new methods to it, in a way that's reminiscent of jQuery:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;from django.db import models
from django.db.models.query import QuerySet
import datetime

class EntryQuerySet(QuerySet):
    def on_date(self, date):
        next = date + datetime.timedelta(days = 1)
        return self.filter(
            posted__gt = date,
            posted__lt = next
        )

class EntryManager(models.Manager):
    def get_query_set(self):
        return EntryQuerySet(self.model)

class Entry(models.Model):
    ...
    objects = EntryManager()&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above gives us a new method on the QuerySets returned by Entry.objects called on_date(), which lets us filter entries down to those posted on a specific date. Now we can run queries like the following:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;Entry.objects.filter(
    category__name = 'Personal'
).on_date(datetime.date(2008, 5, 1))&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Reducing the boilerplate&lt;/h4&gt;

&lt;p&gt;This method works fine, but it requires quite a bit of boilerplate code - a QuerySet subclass and a Manager subclass plus the wiring to pull them all together. Wouldn't it be neat if you could declare the extra QuerySet methods inside the model definition itself?&lt;/p&gt;

&lt;p&gt;It turns out you can, and it's surprisingly easy. Here's the syntax I came up with:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;from django.db.models.query import QuerySet

class Entry(models.Model):
   ...
   objects = QuerySetManager()
   ...
   class QuerySet(QuerySet):
       def on_date(self, date):
           return self.filter(
               ...
           )&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Here I've made the custom QuerySet class an inner class of the model definition. I've also replaced the default manager with a QuerySetManager. All this class does is return the QuerySet inner class for the current model from get_query_set. The implementation looks like this:&lt;/p&gt;

&lt;pre&gt;&lt;code class="python"&gt;class QuerySetManager(models.Manager):
    def get_query_set(self):
        return self.model.QuerySet(self.model)&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I'm pretty happy with this; it makes it trivial to add custom QuerySet methods and does so without any monkeypatching or deep reliance on Django ORM internals. I think the ease with which this can be achieved is a testament to the quality of the ORM API.&lt;/p&gt;
    
        &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/api"&gt;api&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/chaining"&gt;chaining&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/django"&gt;django&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jquery"&gt;jquery&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/orm"&gt;orm&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/queryset"&gt;queryset&lt;/a&gt;&lt;/p&gt;
    

</summary><category term="api"/><category term="chaining"/><category term="django"/><category term="jquery"/><category term="orm"/><category term="python"/><category term="queryset"/></entry><entry><title>Datejs - A JavaScript Date Library</title><link href="https://simonwillison.net/2007/Dec/3/datejs/#atom-tag" rel="alternate"/><published>2007-12-03T21:01:10+00:00</published><updated>2007-12-03T21:01:10+00:00</updated><id>https://simonwillison.net/2007/Dec/3/datejs/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://www.datejs.com/"&gt;Datejs - A JavaScript Date Library&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Building a date API around chaining—Date.today().next().thursday()—is a neat concept. I’d like to see that adapted for Python’s datetime library.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/chaining"&gt;chaining&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datejs"&gt;datejs&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/datetime"&gt;datetime&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/python"&gt;python&lt;/a&gt;&lt;/p&gt;



</summary><category term="chaining"/><category term="datejs"/><category term="datetime"/><category term="javascript"/><category term="python"/></entry><entry><title>dojo.NodeList API docs</title><link href="https://simonwillison.net/2007/Nov/8/nodelist/#atom-tag" rel="alternate"/><published>2007-11-08T11:16:57+00:00</published><updated>2007-11-08T11:16:57+00:00</updated><id>https://simonwillison.net/2007/Nov/8/nodelist/#atom-tag</id><summary type="html">
    
&lt;p&gt;&lt;strong&gt;&lt;a href="http://redesign.dojotoolkit.org/?q=jsdoc/dojo/HEAD/object/dojo.NodeList"&gt;dojo.NodeList API docs&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
Support in Dojo for jQuery-style chaining operations.


    &lt;p&gt;Tags: &lt;a href="https://simonwillison.net/tags/chaining"&gt;chaining&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/dojo"&gt;dojo&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/javascript"&gt;javascript&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/jquery"&gt;jquery&lt;/a&gt;, &lt;a href="https://simonwillison.net/tags/libraries"&gt;libraries&lt;/a&gt;&lt;/p&gt;



</summary><category term="chaining"/><category term="dojo"/><category term="javascript"/><category term="jquery"/><category term="libraries"/></entry></feed>