<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Conditional View Processing — Django 1.5.9 documentation</title> <link rel="stylesheet" href="../_static/default.css" type="text/css" /> <link rel="stylesheet" href="../_static/pygments.css" type="text/css" /> <script type="text/javascript"> var DOCUMENTATION_OPTIONS = { URL_ROOT: '../', VERSION: '1.5.9', COLLAPSE_INDEX: false, FILE_SUFFIX: '.html', HAS_SOURCE: true }; </script> <script type="text/javascript" src="../_static/jquery.js"></script> <script type="text/javascript" src="../_static/underscore.js"></script> <script type="text/javascript" src="../_static/doctools.js"></script> <link rel="top" title="Django 1.5.9 documentation" href="../index.html" /> <link rel="up" title="Using Django" href="index.html" /> <link rel="next" title="Cryptographic signing" href="signing.html" /> <link rel="prev" title="Django’s cache framework" href="cache.html" /> <script type="text/javascript" src="../templatebuiltins.js"></script> <script type="text/javascript"> (function($) { if (!django_template_builtins) { // templatebuiltins.js missing, do nothing. return; } $(document).ready(function() { // Hyperlink Django template tags and filters var base = "../ref/templates/builtins.html"; if (base == "#") { // Special case for builtins.html itself base = ""; } // Tags are keywords, class '.k' $("div.highlight\\-html\\+django span.k").each(function(i, elem) { var tagname = $(elem).text(); if ($.inArray(tagname, django_template_builtins.ttags) != -1) { var fragment = tagname.replace(/_/, '-'); $(elem).html("<a href='" + base + "#" + fragment + "'>" + tagname + "</a>"); } }); // Filters are functions, class '.nf' $("div.highlight\\-html\\+django span.nf").each(function(i, elem) { var filtername = $(elem).text(); if ($.inArray(filtername, django_template_builtins.tfilters) != -1) { var fragment = filtername.replace(/_/, '-'); $(elem).html("<a href='" + base + "#" + fragment + "'>" + filtername + "</a>"); } }); }); })(jQuery); </script> </head> <body> <div class="document"> <div id="custom-doc" class="yui-t6"> <div id="hd"> <h1><a href="../index.html">Django 1.5.9 documentation</a></h1> <div id="global-nav"> <a title="Home page" href="../index.html">Home</a> | <a title="Table of contents" href="../contents.html">Table of contents</a> | <a title="Global index" href="../genindex.html">Index</a> | <a title="Module index" href="../py-modindex.html">Modules</a> </div> <div class="nav"> « <a href="cache.html" title="Django&#8217;s cache framework">previous</a> | <a href="index.html" title="Using Django" accesskey="U">up</a> | <a href="signing.html" title="Cryptographic signing">next</a> »</div> </div> <div id="bd"> <div id="yui-main"> <div class="yui-b"> <div class="yui-g" id="topics-conditional-view-processing"> <div class="section" id="s-conditional-view-processing"> <span id="conditional-view-processing"></span><h1>Conditional View Processing<a class="headerlink" href="#conditional-view-processing" title="Permalink to this headline">¶</a></h1> <p>HTTP clients can send a number of headers to tell the server about copies of a resource that they have already seen. This is commonly used when retrieving a Web page (using an HTTP <tt class="docutils literal"><span class="pre">GET</span></tt> request) to avoid sending all the data for something the client has already retrieved. However, the same headers can be used for all HTTP methods (<tt class="docutils literal"><span class="pre">POST</span></tt>, <tt class="docutils literal"><span class="pre">PUT</span></tt>, <tt class="docutils literal"><span class="pre">DELETE</span></tt>, etc).</p> <p>For each page (response) that Django sends back from a view, it might provide two HTTP headers: the <tt class="docutils literal"><span class="pre">ETag</span></tt> header and the <tt class="docutils literal"><span class="pre">Last-Modified</span></tt> header. These headers are optional on HTTP responses. They can be set by your view function, or you can rely on the <a class="reference internal" href="../ref/middleware.html#django.middleware.common.CommonMiddleware" title="django.middleware.common.CommonMiddleware"><tt class="xref py py-class docutils literal"><span class="pre">CommonMiddleware</span></tt></a> middleware to set the <tt class="docutils literal"><span class="pre">ETag</span></tt> header.</p> <p>When the client next requests the same resource, it might send along a header such as <a class="reference external" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25">If-modified-since</a>, containing the date of the last modification time it was sent, or <a class="reference external" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26">If-none-match</a>, containing the <tt class="docutils literal"><span class="pre">ETag</span></tt> it was sent. If the current version of the page matches the <tt class="docutils literal"><span class="pre">ETag</span></tt> sent by the client, or if the resource has not been modified, a 304 status code can be sent back, instead of a full response, telling the client that nothing has changed.</p> <p>When you need more fine-grained control you may use per-view conditional processing functions.</p> <div class="section" id="s-the-condition-decorator"> <span id="s-conditional-decorators"></span><span id="the-condition-decorator"></span><span id="conditional-decorators"></span><h2>The <tt class="docutils literal"><span class="pre">condition</span></tt> decorator<a class="headerlink" href="#the-condition-decorator" title="Permalink to this headline">¶</a></h2> <p>Sometimes (in fact, quite often) you can create functions to rapidly compute the <a class="reference external" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11">ETag</a> value or the last-modified time for a resource, <strong>without</strong> needing to do all the computations needed to construct the full view. Django can then use these functions to provide an “early bailout” option for the view processing. Telling the client that the content has not been modified since the last request, perhaps.</p> <p>These two functions are passed as parameters the <tt class="docutils literal"><span class="pre">django.views.decorators.http.condition</span></tt> decorator. This decorator uses the two functions (you only need to supply one, if you can’t compute both quantities easily and quickly) to work out if the headers in the HTTP request match those on the resource. If they don’t match, a new copy of the resource must be computed and your normal view is called.</p> <p>The <tt class="docutils literal"><span class="pre">condition</span></tt> decorator’s signature looks like this:</p> <div class="highlight-python"><div class="highlight"><pre><span class="n">condition</span><span class="p">(</span><span class="n">etag_func</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="n">last_modified_func</span><span class="o">=</span><span class="bp">None</span><span class="p">)</span> </pre></div> </div> <p>The two functions, to compute the ETag and the last modified time, will be passed the incoming <tt class="docutils literal"><span class="pre">request</span></tt> object and the same parameters, in the same order, as the view function they are helping to wrap. The function passed <tt class="docutils literal"><span class="pre">last_modified_func</span></tt> should return a standard datetime value specifying the last time the resource was modified, or <tt class="docutils literal"><span class="pre">None</span></tt> if the resource doesn’t exist. The function passed to the <tt class="docutils literal"><span class="pre">etag</span></tt> decorator should return a string representing the <a class="reference external" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.11">Etag</a> for the resource, or <tt class="docutils literal"><span class="pre">None</span></tt> if it doesn’t exist.</p> <p>Using this feature usefully is probably best explained with an example. Suppose you have this pair of models, representing a simple blog system:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">import</span> <span class="nn">datetime</span> <span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span> <span class="k">class</span> <span class="nc">Blog</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span> <span class="o">...</span> <span class="k">class</span> <span class="nc">Entry</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span> <span class="n">blog</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">ForeignKey</span><span class="p">(</span><span class="n">Blog</span><span class="p">)</span> <span class="n">published</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">(</span><span class="n">default</span><span class="o">=</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">)</span> <span class="o">...</span> </pre></div> </div> <p>If the front page, displaying the latest blog entries, only changes when you add a new blog entry, you can compute the last modified time very quickly. You need the latest <tt class="docutils literal"><span class="pre">published</span></tt> date for every entry associated with that blog. One way to do this would be:</p> <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">latest_entry</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">blog_id</span><span class="p">):</span> <span class="k">return</span> <span class="n">Entry</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">blog</span><span class="o">=</span><span class="n">blog_id</span><span class="p">)</span><span class="o">.</span><span class="n">latest</span><span class="p">(</span><span class="s">"published"</span><span class="p">)</span><span class="o">.</span><span class="n">published</span> </pre></div> </div> <p>You can then use this function to provide early detection of an unchanged page for your front page view:</p> <div class="highlight-python"><div class="highlight"><pre><span class="kn">from</span> <span class="nn">django.views.decorators.http</span> <span class="kn">import</span> <span class="n">condition</span> <span class="nd">@condition</span><span class="p">(</span><span class="n">last_modified_func</span><span class="o">=</span><span class="n">latest_entry</span><span class="p">)</span> <span class="k">def</span> <span class="nf">front_page</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">blog_id</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> </div> <div class="section" id="s-shortcuts-for-only-computing-one-value"> <span id="shortcuts-for-only-computing-one-value"></span><h2>Shortcuts for only computing one value<a class="headerlink" href="#shortcuts-for-only-computing-one-value" title="Permalink to this headline">¶</a></h2> <p>As a general rule, if you can provide functions to compute <em>both</em> the ETag and the last modified time, you should do so. You don’t know which headers any given HTTP client will send you, so be prepared to handle both. However, sometimes only one value is easy to compute and Django provides decorators that handle only ETag or only last-modified computations.</p> <p>The <tt class="docutils literal"><span class="pre">django.views.decorators.http.etag</span></tt> and <tt class="docutils literal"><span class="pre">django.views.decorators.http.last_modified</span></tt> decorators are passed the same type of functions as the <tt class="docutils literal"><span class="pre">condition</span></tt> decorator. Their signatures are:</p> <div class="highlight-python"><div class="highlight"><pre><span class="n">etag</span><span class="p">(</span><span class="n">etag_func</span><span class="p">)</span> <span class="n">last_modified</span><span class="p">(</span><span class="n">last_modified_func</span><span class="p">)</span> </pre></div> </div> <p>We could write the earlier example, which only uses a last-modified function, using one of these decorators:</p> <div class="highlight-python"><div class="highlight"><pre><span class="nd">@last_modified</span><span class="p">(</span><span class="n">latest_entry</span><span class="p">)</span> <span class="k">def</span> <span class="nf">front_page</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">blog_id</span><span class="p">):</span> <span class="o">...</span> </pre></div> </div> <p>...or:</p> <div class="highlight-python"><div class="highlight"><pre><span class="k">def</span> <span class="nf">front_page</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="n">blog_id</span><span class="p">):</span> <span class="o">...</span> <span class="n">front_page</span> <span class="o">=</span> <span class="n">last_modified</span><span class="p">(</span><span class="n">latest_entry</span><span class="p">)(</span><span class="n">front_page</span><span class="p">)</span> </pre></div> </div> <div class="section" id="s-use-condition-when-testing-both-conditions"> <span id="use-condition-when-testing-both-conditions"></span><h3>Use <tt class="docutils literal"><span class="pre">condition</span></tt> when testing both conditions<a class="headerlink" href="#use-condition-when-testing-both-conditions" title="Permalink to this headline">¶</a></h3> <p>It might look nicer to some people to try and chain the <tt class="docutils literal"><span class="pre">etag</span></tt> and <tt class="docutils literal"><span class="pre">last_modified</span></tt> decorators if you want to test both preconditions. However, this would lead to incorrect behavior.</p> <div class="highlight-python"><pre># Bad code. Don't do this! @etag(etag_func) @last_modified(last_modified_func) def my_view(request): # ... # End of bad code.</pre> </div> <p>The first decorator doesn’t know anything about the second and might answer that the response is not modified even if the second decorators would determine otherwise. The <tt class="docutils literal"><span class="pre">condition</span></tt> decorator uses both callback functions simultaneously to work out the right action to take.</p> </div> </div> <div class="section" id="s-using-the-decorators-with-other-http-methods"> <span id="using-the-decorators-with-other-http-methods"></span><h2>Using the decorators with other HTTP methods<a class="headerlink" href="#using-the-decorators-with-other-http-methods" title="Permalink to this headline">¶</a></h2> <p>The <tt class="docutils literal"><span class="pre">condition</span></tt> decorator is useful for more than only <tt class="docutils literal"><span class="pre">GET</span></tt> and <tt class="docutils literal"><span class="pre">HEAD</span></tt> requests (<tt class="docutils literal"><span class="pre">HEAD</span></tt> requests are the same as <tt class="docutils literal"><span class="pre">GET</span></tt> in this situation). It can also be used to provide checking for <tt class="docutils literal"><span class="pre">POST</span></tt>, <tt class="docutils literal"><span class="pre">PUT</span></tt> and <tt class="docutils literal"><span class="pre">DELETE</span></tt> requests. In these situations, the idea isn’t to return a “not modified” response, but to tell the client that the resource they are trying to change has been altered in the meantime.</p> <p>For example, consider the following exchange between the client and server:</p> <ol class="arabic simple"> <li>Client requests <tt class="docutils literal"><span class="pre">/foo/</span></tt>.</li> <li>Server responds with some content with an ETag of <tt class="docutils literal"><span class="pre">"abcd1234"</span></tt>.</li> <li>Client sends an HTTP <tt class="docutils literal"><span class="pre">PUT</span></tt> request to <tt class="docutils literal"><span class="pre">/foo/</span></tt> to update the resource. It also sends an <tt class="docutils literal"><span class="pre">If-Match:</span> <span class="pre">"abcd1234"</span></tt> header to specify the version it is trying to update.</li> <li>Server checks to see if the resource has changed, by computing the ETag the same way it does for a <tt class="docutils literal"><span class="pre">GET</span></tt> request (using the same function). If the resource <em>has</em> changed, it will return a 412 status code code, meaning “precondition failed”.</li> <li>Client sends a <tt class="docutils literal"><span class="pre">GET</span></tt> request to <tt class="docutils literal"><span class="pre">/foo/</span></tt>, after receiving a 412 response, to retrieve an updated version of the content before updating it.</li> </ol> <p>The important thing this example shows is that the same functions can be used to compute the ETag and last modification values in all situations. In fact, you <strong>should</strong> use the same functions, so that the same values are returned every time.</p> </div> <div class="section" id="s-comparison-with-middleware-conditional-processing"> <span id="comparison-with-middleware-conditional-processing"></span><h2>Comparison with middleware conditional processing<a class="headerlink" href="#comparison-with-middleware-conditional-processing" title="Permalink to this headline">¶</a></h2> <p>You may notice that Django already provides simple and straightforward conditional <tt class="docutils literal"><span class="pre">GET</span></tt> handling via the <a class="reference internal" href="../ref/middleware.html#django.middleware.http.ConditionalGetMiddleware" title="django.middleware.http.ConditionalGetMiddleware"><tt class="xref py py-class docutils literal"><span class="pre">django.middleware.http.ConditionalGetMiddleware</span></tt></a> and <a class="reference internal" href="../ref/middleware.html#django.middleware.common.CommonMiddleware" title="django.middleware.common.CommonMiddleware"><tt class="xref py py-class docutils literal"><span class="pre">CommonMiddleware</span></tt></a>. Whilst certainly being easy to use and suitable for many situations, those pieces of middleware functionality have limitations for advanced usage:</p> <ul class="simple"> <li>They are applied globally to all views in your project</li> <li>They don’t save you from generating the response itself, which may be expensive</li> <li>They are only appropriate for HTTP <tt class="docutils literal"><span class="pre">GET</span></tt> requests.</li> </ul> <p>You should choose the most appropriate tool for your particular problem here. If you have a way to compute ETags and modification times quickly and if some view takes a while to generate the content, you should consider using the <tt class="docutils literal"><span class="pre">condition</span></tt> decorator described in this document. If everything already runs fairly quickly, stick to using the middleware and the amount of network traffic sent back to the clients will still be reduced if the view hasn’t changed.</p> </div> </div> </div> </div> </div> <div class="yui-b" id="sidebar"> <div class="sphinxsidebar"> <div class="sphinxsidebarwrapper"> <h3><a href="../contents.html">Table Of Contents</a></h3> <ul> <li><a class="reference internal" href="#">Conditional View Processing</a><ul> <li><a class="reference internal" href="#the-condition-decorator">The <tt class="docutils literal"><span class="pre">condition</span></tt> decorator</a></li> <li><a class="reference internal" href="#shortcuts-for-only-computing-one-value">Shortcuts for only computing one value</a><ul> <li><a class="reference internal" href="#use-condition-when-testing-both-conditions">Use <tt class="docutils literal"><span class="pre">condition</span></tt> when testing both conditions</a></li> </ul> </li> <li><a class="reference internal" href="#using-the-decorators-with-other-http-methods">Using the decorators with other HTTP methods</a></li> <li><a class="reference internal" href="#comparison-with-middleware-conditional-processing">Comparison with middleware conditional processing</a></li> </ul> </li> </ul> <h3>Browse</h3> <ul> <li>Prev: <a href="cache.html">Django’s cache framework</a></li> <li>Next: <a href="signing.html">Cryptographic signing</a></li> </ul> <h3>You are here:</h3> <ul> <li> <a href="../index.html">Django 1.5.9 documentation</a> <ul><li><a href="index.html">Using Django</a> <ul><li>Conditional View Processing</li></ul> </li></ul> </li> </ul> <h3>This Page</h3> <ul class="this-page-menu"> <li><a href="../_sources/topics/conditional-view-processing.txt" rel="nofollow">Show Source</a></li> </ul> <div id="searchbox" style="display: none"> <h3>Quick search</h3> <form class="search" action="../search.html" method="get"> <input type="text" name="q" /> <input type="submit" value="Go" /> <input type="hidden" name="check_keywords" value="yes" /> <input type="hidden" name="area" value="default" /> </form> <p class="searchtip" style="font-size: 90%"> Enter search terms or a module, class or function name. </p> </div> <script type="text/javascript">$('#searchbox').show(0);</script> </div> </div> <h3>Last update:</h3> <p class="topless">Aug 21, 2014</p> </div> </div> <div id="ft"> <div class="nav"> « <a href="cache.html" title="Django&#8217;s cache framework">previous</a> | <a href="index.html" title="Using Django" accesskey="U">up</a> | <a href="signing.html" title="Cryptographic signing">next</a> »</div> </div> </div> <div class="clearer"></div> </div> </body> </html>