<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>Passing Curiosity: Posts tagged decorators</title>
    <link href="https://passingcuriosity.com/tags/decorators/decorators.xml" rel="self" />
    <link href="https://passingcuriosity.com" />
    <id>https://passingcuriosity.com/tags/decorators/decorators.xml</id>
    <author>
        <name>Thomas Sutton</name>
        
        <email>me@thomas-sutton.id.au</email>
        
    </author>
    <updated>2009-07-20T00:00:00Z</updated>
    <entry>
    <title>Writing view decorators for Django</title>
    <link href="https://passingcuriosity.com/2009/writing-view-decorators-for-django/" />
    <id>https://passingcuriosity.com/2009/writing-view-decorators-for-django/</id>
    <published>2009-07-20T00:00:00Z</published>
    <updated>2009-07-20T00:00:00Z</updated>
    <summary type="html"><![CDATA[<p>Using decorators to wrap and modify Django views is quick, easy, composable,
and just about the most awesome thing I’ve seen in a while. It also takes a
little bit of figuring out. Here’s my explanation…</p>
<h2 id="more-than-just-decoration">More than just decoration</h2>
<p>Using a decorator looks (in Python) like this:</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="at">@a_decorator</span></span>
<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> a_function(an_arg):</span>
<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> <span class="st">&quot;Functionate: </span><span class="sc">%s</span><span class="st">!&quot;</span> <span class="op">%</span> (an_arg)</span></code></pre></div>
<p>Where <code>a_decorator</code> is some function or other which takes an argument
(<code>a_function</code>, in this particular case) and returns a value. When Python loads
a module containing this code it creates a new function <code>a_function</code> as
normal, but then it calls <code>a_decorator</code> on it and binds the value it returns
to the name <code>a_function</code> rather than the original function created from the
definition. So how do we write these decorators? Just like a normal function!</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> a_decorator(the_func):</span>
<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">&quot;&quot;&quot;</span></span>
<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="co">    Make another a function more beautiful.</span></span>
<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="co">    &quot;&quot;&quot;</span></span>
<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">def</span> _decorated(<span class="op">*</span>args, <span class="op">**</span>kwargs):</span>
<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> the_func(<span class="op">*</span>args, <span class="op">**</span>kwargs)</span>
<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> _decorated</span></code></pre></div>
<p>But what about parameterised decorators? It’s just a little more involved.
Recall that you use a decorator like this: <code>@the_decorator</code>. It turns out that
such decorator statements don’t just <em>name</em> a decorator to be called, but can
also call a function to return a decorator to be called:</p>
<div class="sourceCode" id="cb3"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> wrap_in_a(tag):</span>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">&quot;&quot;&quot;</span></span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="co">    Wrap the result of a function in a `tag` HTML tag.</span></span>
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="co">    &quot;&quot;&quot;</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>    <span class="kw">def</span> _dec(func):</span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>        <span class="kw">def</span> _new_func(<span class="op">*</span>args, <span class="op">**</span>kwargs):</span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>            <span class="cf">return</span> <span class="st">&quot;&lt;</span><span class="sc">%s</span><span class="st">&gt;</span><span class="sc">%s</span><span class="st">&lt;/</span><span class="sc">%s</span><span class="st">&gt;&quot;</span> <span class="op">%</span> (tag, func(<span class="op">*</span>args, <span class="op">**</span>kwargs), tag)</span>
<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> _new_func</span>
<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> _dec</span>
<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a><span class="at">@wrap_in_a</span>(<span class="st">'div'</span>)</span>
<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a><span class="at">@login_required</span></span>
<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> my_name(request):</span>
<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> request.user.first_name</span></code></pre></div>
<p>The first decorator statement <code>@wrap_in_a('div')</code> calls <code>wrap_in_a('div')</code>
which returns a function (<code>_dec</code>). This function is then applied to the
following definition (<code>@login_required</code> applied to <code>my_name</code>). Simple!</p>
<p>It’s probably a good idea to add a few more bits and pieces to the function
returned by a decorator (copying <code>__doc__</code> and <code>__dict__</code>, for instance), but
that’s the core of it.</p>
<h2 id="using-it-in-django">Using it in Django</h2>
<p>So this is all pretty cool, but how do we use it in Django? We’ll here’s a
<code>anonymous_required</code> decorator that you can use to redirect authenticated
users to their home page if they try to login again:</p>
<div class="sourceCode" id="cb4"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> anonymous_required(function<span class="op">=</span><span class="va">None</span>, home_url<span class="op">=</span><span class="va">None</span>, redirect_field_name<span class="op">=</span><span class="va">None</span>):</span>
<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>    <span class="co">&quot;&quot;&quot;Check that the user is NOT logged in.</span></span>
<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">    This decorator ensures that the view functions it is called on can be </span></span>
<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="co">    accessed only by anonymous users. When an authenticated user accesses</span></span>
<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="co">    such a protected view, they are redirected to the address specified in </span></span>
<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="co">    the field named in `next_field` or, lacking such a value, the URL in </span></span>
<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="co">    `home_url`, or the `USER_HOME_URL` setting.</span></span>
<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="co">    &quot;&quot;&quot;</span></span>
<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> home_url <span class="kw">is</span> <span class="va">None</span>:</span>
<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a>        home_url <span class="op">=</span> settings.USER_HOME_URL</span>
<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a>    <span class="kw">def</span> _dec(view_func):</span>
<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a>        <span class="kw">def</span> _view(request, <span class="op">*</span>args, <span class="op">**</span>kwargs):</span>
<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a>            <span class="cf">if</span> request.user.is_authenticated():</span>
<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a>                url <span class="op">=</span> <span class="va">None</span></span>
<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a>                <span class="cf">if</span> redirect_field_name <span class="kw">and</span> redirect_field_name <span class="kw">in</span> request.REQUEST:</span>
<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a>                    url <span class="op">=</span> request.REQUEST[redirect_field_name]</span>
<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>                <span class="cf">if</span> <span class="kw">not</span> url:</span>
<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a>                    url <span class="op">=</span> home_url</span>
<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a>                <span class="cf">if</span> <span class="kw">not</span> url:</span>
<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>                    url <span class="op">=</span> <span class="st">&quot;/&quot;</span></span>
<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>                <span class="cf">return</span> HttpResponseRedirect(url)</span>
<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a>            <span class="cf">else</span>:</span>
<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a>                <span class="cf">return</span> view_func(request, <span class="op">*</span>args, <span class="op">**</span>kwargs)</span>
<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a>        _view.<span class="va">__name__</span> <span class="op">=</span> view_func.<span class="va">__name__</span></span>
<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>        _view.__dict__ <span class="op">=</span> view_func.__dict__</span>
<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a>        _view.__doc__ <span class="op">=</span> view_func.__doc__</span>
<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> _view</span>
<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a>    <span class="cf">if</span> function <span class="kw">is</span> <span class="va">None</span>:</span>
<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> _dec</span>
<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a>    <span class="cf">else</span>:</span>
<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a>        <span class="cf">return</span> _dec(function)</span></code></pre></div>
<p>It’s probably not very Django-ish, but you get the impression. Just use it
like Django’s built-in <code>login_required</code> decorator:</p>
<div class="sourceCode" id="cb5"><pre class="sourceCode python"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="at">@anonynous_required</span></span>
<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> a_view(request):</span>
<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a>    <span class="cf">return</span> HttpResponse(<span class="st">&quot;We are anonymous! We are legion!&quot;</span>)</span></code></pre></div>
<p>Comments and suggestions welcome!</p>
<p><strong>Update:</strong> Amended the example decorator above to work correctly as
<code>@anonymous_required</code>, <code>@anonymous_required(...)</code> or <code>foo = anonymous_required(foo)</code>.</p>]]></summary>
</entry>

</feed>
