<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0"><channel><atom:link rel="hub" href="http://tumblr.superfeedr.com/" xmlns:atom="http://www.w3.org/2005/Atom"/><description></description><title>djangozen</title><generator>Tumblr (3.0; @djangozen)</generator><link>http://djangozen.com/</link><item><title>Faster or lazier pagination</title><description>&lt;p&gt;&lt;strong&gt;Or how to avoid slow counts in Postgres.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is a paginator that does not do a count and it all started with this &lt;a href="http://www.agmweb.ca/blog/andy/2226/"&gt;blog post&lt;/a&gt;. Essentially &lt;a href="http://areciboapp.com"&gt;Arecibo&lt;/a&gt; was getting hammered by the number of the requests that were being sent to it. It wasn’t the requests that were the problem, is the listing of them.&lt;/p&gt;
&lt;p&gt;I was doing all the usual stuff, vacuuming and making indexes. However those counts were still slow and the indexes were not always being used. So mmalone had a good idea and an excellent &lt;a href="http://gist.github.com/213702"&gt;gist&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Taking this, I updated it for the latest Django and we got the LazyPaginator.&lt;/p&gt;
&lt;p&gt;Example from a normal Paginator:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; from django.db import connection
&gt;&gt;&gt; from listener.models.error import Error
&gt;&gt;&gt; queryset = Error.objects.filter(account=1, archived=1)&lt;/pre&gt;
&lt;p&gt;The old way:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; from django.core.paginator import Paginator 
&gt;&gt;&gt; p = Paginator(queryset, 10)
&gt;&gt;&gt; p.page(1)
&lt;Page 1 of 859&gt;&lt;/pre&gt;
&lt;p&gt;Causes:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; connection.queries
[ {'time': '21.953', 'sql': 'SELECT COUNT(*) FROM "listener_error" 
   WHERE ("listener_error"."account_id" = 1  
   AND "listener_error"."archived" = true )'}]&lt;/pre&gt;
&lt;p&gt;That’s one query. To get the object list it does another.&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; p.page(1).object_list
[{'time': '0.000', 'sql': 'SELECT "listener_error"."id", ... FROM "listener_error"
    WHERE ("listener_error"."account_id" = 1  
    AND "listener_error"."archived" = true ) LIMIT 10'}]&lt;/pre&gt;
&lt;p&gt;The problem is that count can be hideously expensive. At one point, it was about 15 minutes.&lt;/p&gt;
&lt;p&gt;The new way:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; from lazy_paginator.paginator import LazyPaginator 
&gt;&gt;&gt; p = LazyPaginator(queryset, 10)
&gt;&gt;&gt; p.page(1)
&lt;Page 1 of 1000&gt;&lt;/pre&gt;
&lt;pre&gt;&gt;&gt;&gt; connection.queries     
[{'time': '0.000', 'sql': 'SELECT "listener_error"."id",... FROM "listener_error" 
   WHERE ("listener_error"."account_id" = 1  
   AND "listener_error"."archived" = true ) LIMIT 11'}]&lt;/pre&gt;
&lt;pre&gt;&gt;&gt;&gt; p.page(1).object_list
[{'time': '0.000', 'sql': 'SELECT "listener_error"."id",... FROM "listener_error"
    WHERE ("listener_error"."account_id" = 1  
    AND "listener_error"."archived" = true ) LIMIT 10'}]&lt;/pre&gt;
&lt;p&gt;By doing a query for one more than you need, it figures out if there’s a next. The difference is the select vs the count.&lt;/p&gt;
&lt;p&gt;What do you lose? You don’t know how many records there are, you just know if there is a next and previous (and you can figure out how many came before). But if you are using postgresql, beware of how expensive those counts can be.&lt;/p&gt;
&lt;p&gt;The default assumes there’s going to be 1000 pages, but we don’t really know how many there. There’s a max_safe_pages variable that gets updated as information is provided. For example if you set it to 3 pages… when try and access 4, it fail, thinking that there was no data.&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; p = LazyPaginator(queryset, 10, max_safe_pages=3)
&gt;&gt;&gt; p.has_next(1)
True
&gt;&gt;&gt; p.has_next(2)
True
&gt;&gt;&gt; p.has_next(3)
False
&gt;&gt;&gt; p.has_next(4)
False
&gt;&gt;&gt; p.page(4)    
Traceback (most recent call last):
  File "", line 1, in 
  File "/var/arecibo/lazy_paginator/paginator.py", line 27, in page
    number = self.validate_number(number)
  File "/var/arecibo/lazy_paginator/paginator.py", line 20, in validate_number
    return super(LazyPaginator, self).validate_number(number)
  File "/usr/lib/python2.5/site-packages/django/core/paginator.py", line 32, in validate_number
    raise EmptyPage('That page contains no results')
EmptyPage: That page contains no results&lt;/pre&gt;
&lt;p&gt;Now if you start at the beginning:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; p.page(2)

&gt;&gt;&gt; p.page(3)

&gt;&gt;&gt; p.page(4)
&lt;Page 4 of 5&gt;&lt;/pre&gt;
&lt;p&gt;That can be a bit confusing, perhaps in the future it should check and if not then try to get it… improvements welcome.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Install:&lt;/strong&gt; Lazy paginator can be installed from &lt;a href="http://pypi.python.org/pypi/lazy_paginator/0.1"&gt;PyPi&lt;/a&gt; or on &lt;a href="http://github.com/andymckay/lazy_paginator"&gt;github&lt;/a&gt;.&lt;/p&gt;</description><link>http://djangozen.com/post/14347177161</link><guid>http://djangozen.com/post/14347177161</guid><pubDate>Sat, 17 Dec 2011 03:15:30 -0500</pubDate></item><item><title>The power of Q</title><description>&lt;p&gt;&lt;strong&gt;Q objects are a great tool in Django.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="No not that Q" src="http://farm1.static.flickr.com/27/102561423_542f594517_m.jpg"/&gt;&lt;/p&gt;
&lt;p&gt;&lt;a class="external-link" href="http://docs.djangoproject.com/en/dev/topics/db/queries/#complex-lookups-with-q-objects"&gt;Q objects&lt;/a&gt; are lumbered with a name that’s very hard to Google. Down there with &lt;a class="external-link" href="http://docs.djangoproject.com/en/dev/topics/db/queries/#filters-can-reference-fields-on-the-model"&gt;F objects&lt;/a&gt; and &lt;a class="external-link" href="http://plone.org/documentation/kb/embrace-and-extend-the-zope-3-way/event-handler"&gt;Plone’s event&lt;/a&gt;. You’ll probably come across Q objects when you need to complicated lookups such as &lt;em&gt;not&lt;/em&gt;, &lt;em&gt;or &lt;/em&gt;and so on. But these objects are so useful.&lt;/p&gt;
&lt;h3&gt;Complex lookups&lt;/h3&gt;
&lt;p&gt;You can make Q objects for the lookups you’d like. For example:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; from django.db.models import Q
&gt;&gt;&gt; from listener.models.error import Error # our example model&lt;/pre&gt;
&lt;p&gt;To find all objects that archived and have a priority of 1, we could do:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; Error.objects.filter(archived=False).filter(priority=1).count()
39592&lt;/pre&gt;
&lt;p&gt;The equivalent in Q objects is:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; Error.objects.filter(Q(archived=False) &amp; Q(priority=1)).count()
39592&lt;/pre&gt;
&lt;p&gt;But now we can at least do an or quite easily (archived or have a priority of 1):&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; Error.objects.filter(Q(archived=False) | Q(priority=1)).count()
195871&lt;/pre&gt;
&lt;p&gt;And how about archived and a priority of not 1:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; Error.objects.filter(Q(archived=False) &amp; ~Q(priority=1)).count()
41545&lt;/pre&gt;
&lt;h3&gt;List of lookups&lt;/h3&gt;
&lt;p&gt;One thing I do quite often is build up the query dynamically. You can do that easily in Python by making a dictionary and passing that to filter. You can also do it by building up a list of Q objects. For example:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; qs = [Q(archived=False),]
&gt;&gt;&gt; qs.append(Q(priority=1))
&gt;&gt;&gt; qs
[&lt;django.db.models.query_utils.Q object at 0x17a0d90&gt;, &lt;django.db.models.query_utils.Q object at 0x17a0d50&gt;]&lt;/pre&gt;
&lt;p&gt;We’ve now got a list of Q objects and we can do a filter. The use of reduce and operator.or_, applies the | to all the elements in the list:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; import operator
&gt;&gt;&gt; Error.objects.filter(reduce(operator.or_, qs)).count()
195871&lt;/pre&gt;
&lt;p&gt;Similarly for an and:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; Error.objects.filter(reduce(operator.and_, qs)).count()
39592&lt;/pre&gt;
&lt;h3&gt;Pickling lookups&lt;/h3&gt;
&lt;p&gt;If you would like to store your lookups you can pickle the list of objects. This means you can save the Q objects and use them again later. For example:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; import pickle
&gt;&gt;&gt; saved = pickle.dumps(qs)
&gt;&gt;&gt; Error.objects.filter(reduce(operator.and_, pickle.loads(saved))).count()
39592&lt;/pre&gt;
&lt;p&gt;Pickling is a useful way of saving the queries for use again later. In some situations it can be benefical to pickle the queries as opposed to pickling the results. Django documentation notes that “If you pickle a QuerySet, this will force all the results to be loaded into memory prior to pickling.” (&lt;a class="external-link" href="http://docs.djangoproject.com/en/dev/ref/models/querysets/#id2"&gt;docs&lt;/a&gt;).&lt;/p&gt;</description><link>http://djangozen.com/post/14347160603</link><guid>http://djangozen.com/post/14347160603</guid><pubDate>Sat, 17 Dec 2011 03:14:36 -0500</pubDate></item><item><title>Javascript inline forms outside of contrib.admin</title><description>&lt;p&gt;&lt;strong&gt;This recipe follows on from the last two and shows how to do the addition of inline fields to a model form, outside of contrib.admin.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="notice"&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: this is excerpt a recipe from cleardjango. You can download the &lt;a href="http://code.google.com/p/cleardjango/source/checkout"&gt;source from SVN&lt;/a&gt;. Once you’ve checked it out, do: &lt;span class="pre"&gt;python&lt;/span&gt; &lt;span class="pre"&gt;tools/configure.py&lt;/span&gt; &lt;span class="pre"&gt;-s&lt;/span&gt; &lt;span class="pre"&gt;72&lt;/span&gt; to install and run this recipe.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;In the last two recipes, we’ve seen how to add inlines through the admin interface. We’ll repeat this process in this last recipe of the series but without the admin interface. This uses some different API’s and therefore can be slightly different. Again, we’ll show a quick snippet of the end result:&lt;/p&gt;
&lt;p&gt;&lt;img alt="_images/recipe_72.jpg" src="http://cleardjango.googlecode.com/svn/trunk/text/media//recipe_72.jpg"/&gt;&lt;/p&gt;
&lt;p&gt;The models have remain unchanged since recipe 70. The forms for this setup will also be similar to recipe 70. We’ll just need to add in one new form - the Recipe form. This is a basic Django ModelForm:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;forms&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;recipe_72.models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Recipe&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecipeForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelForm&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Recipe&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ingredient_form_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"other_recipe"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;formfield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;formfield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We’ll set up two URLs for this recipe, one to add and one to add:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecipeForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forms&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelForm&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Meta&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The add template is pretty straightforward. We are going to assume that the view is passing a form (the Recipe form) and a formset (the Ingredient formset) to the template. Notice in the template that I’ve used the same classes from the admin in order to make the Javascript a little bit easier. Each formset is also rendered in its own table. This makes for a slightly ugly markup but it works.&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;pre&gt;                  {{ formsets.management_form }}
                  {% for formset in formsets.forms %}
                  &lt;table&gt;
                      {{ formset }}
                  &lt;/table&gt;
                  {% endfor %}&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;When rendering a formset manually in this manner, we also need to include the management form (line 1). This form is the value that gets incremented every time &lt;em&gt;Add another row&lt;/em&gt; is pressed &lt;a class="footnote-reference" href="#f1" id="id1"&gt;[1]&lt;/a&gt;. The JavaScript is very similar to the one from recipe 72 with a few minor alterations. Since we now have control over the template, the button is rendered in the template not the JavaScript.&lt;/p&gt;
&lt;p&gt;Those are all the elements. Now we need to take a look at the main part of this recipe, the views. I covered how to use the &lt;em&gt;formfield_callback&lt;/em&gt; and &lt;em&gt;curry&lt;/em&gt; to process the field correctly in recipe 70 . We’ll repeat this process in our view. The admin won’t be constructing the formset for us this time. We’ll have to construct it using an &lt;em&gt;inlineformset_factory&lt;/em&gt; &lt;a class="footnote-reference" href="#f2" id="id2"&gt;[2]&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;    &lt;span class="n"&gt;IngredientFormSet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inlineformset_factory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="n"&gt;fk_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"recipe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
                &lt;span class="n"&gt;formfield_callback&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredient_form_callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once we’ve got that formset built, most of the rest of the form is straightforward and follows the standard form population, validation and save process. One slight wrinkle is before the formset can be saved we’ll need a recipe to link to it. For this reason, the view populates the formset, validates it, then repopulates it with the saved recipe:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;        &lt;span class="n"&gt;form&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RecipeForm&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;formset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IngredientFormSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;formset&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
            &lt;span class="n"&gt;recipe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;form&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;save&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="n"&gt;formset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IngredientFormSet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;POST&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;recipe&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;There’s little difference for the edit page and most of that should be familiar by now. Since we ended up using the &lt;em&gt;formfield_callback&lt;/em&gt;, it’s easy to have these models editable in both &lt;em&gt;the admin&lt;/em&gt; and &lt;em&gt;outside the admin&lt;/em&gt;.&lt;/p&gt;
&lt;div class="success"&gt;
&lt;p&gt;&lt;strong&gt;Sponsored Recipe&lt;/strong&gt;: This recipe was sponsored by &lt;a class="reference external" href="http://www.bluefountain.com/"&gt;Blue Fountain Systems Ltd&lt;/a&gt;. Please contact &lt;a class="reference external" href="http://www.clearwind.ca"&gt;Clearwind&lt;/a&gt; if you’d like to sponsor a recipe.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a class="fn-backref" href="#id1"&gt;[1]&lt;/a&gt; &lt;a class="reference external" href="http://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-a-formset-in-views-and-templates"&gt;&lt;a href="http://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-a-formset-in-views-and-templates"&gt;http://docs.djangoproject.com/en/dev/topics/forms/formsets/#using-a-formset-in-views-and-templates&lt;/a&gt;&lt;/a&gt; &lt;a class="fn-backref" href="#id2"&gt;[2]&lt;/a&gt; &lt;a class="reference external" href="http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets"&gt;&lt;a href="http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets"&gt;http://docs.djangoproject.com/en/dev/topics/forms/modelforms/#inline-formsets&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;</description><link>http://djangozen.com/post/14347138573</link><guid>http://djangozen.com/post/14347138573</guid><pubDate>Sat, 17 Dec 2011 03:13:00 -0500</pubDate></item><item><title>Adding Javascript to contrib.admin inline fields</title><description>&lt;p&gt;&lt;strong&gt;This recipe follows on from the last by adding Javascript to the inline fields of a model in the contrib.admin.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="notice"&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: this is excerpt a recipe from cleardjango. You can download the &lt;a href="http://code.google.com/p/cleardjango/source/checkout"&gt;source from SVN&lt;/a&gt;. Once you’ve checked it out, do: &lt;span class="pre"&gt;python&lt;/span&gt; &lt;span class="pre"&gt;tools/configure.py&lt;/span&gt; &lt;span class="pre"&gt;-s&lt;/span&gt; &lt;span class="pre"&gt;71&lt;/span&gt; to install and run this recipe.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;By default the inlines in contrib.admin are a fixed number. In each case Django adds in three extra ingredient inlines for you by default. However, a user may add in more. What we really need is an Javascript solution to add in more rows so the user can keep adding extra rows in one page.&lt;/p&gt;
&lt;p&gt;There are two ways to do this. One way is to use the &lt;em&gt;template&lt;/em&gt; parameter of the admin.TabularInline. You could add in a new template to display the entire inline field set using this. You’d want to go grab the inline template and then place it in your project to do this. Then you could customize it to add a button and some JavaScript. You can see this in the &lt;em&gt;templates&lt;/em&gt; directory of this recipe.&lt;/p&gt;
&lt;p&gt;I didn’t choose that way because it involves the copy and paste of large amounts of Django template code. Remember template code can change and you’ll need to maintain that template code across upgrades. The only real advantage of doing that copy and paste is to include a snippet of JavaScript and a bit of HTML. The JavaScript shouldn’t be in the template and should be in an external file anyway. So this is really a less desirable solution.&lt;/p&gt;
&lt;p&gt;You’ll see what I chose to do instead in the &lt;em&gt;media&lt;/em&gt; folder of this recipe. Take a look at the &lt;em&gt;add_tabular_inline.js&lt;/em&gt; file. This uses jQuery to add an add button and then clone the last row of the inlines.&lt;/p&gt;
&lt;p&gt;Let’s setup the JavaScript. You can add custom JavaScript using the Media class inside RecipeAdmin. This particular one pulls in jQuery from Google’s servers and then the JavaScript from our recipe &lt;a class="footnote-reference" href="#f1" id="id1"&gt;[1]&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Media&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;js&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"/recipe_media/add_tabular_inline.js"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The JavaScript creates a button and then binds a clone event to it. This works with the &lt;em&gt;TabularInline&lt;/em&gt;. A &lt;em&gt;StackedInline&lt;/em&gt; would require slightly different code. This isn’t much longer at all compared to the embedding in the template version:&lt;/p&gt;
&lt;div class="highlight-javascript"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;increment_form_ids&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;from&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;':input'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="nx"&gt;each&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
          &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;old_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;old_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'name'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;old_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'id'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;old_id&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;from&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
          &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
 
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;add_inline_button&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".inline-group p.tools"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"click"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;parents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"div.inline-group"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"tr"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;copy&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hasClass&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"row1"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"row2"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;attr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"class"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"row1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;last&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;after&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;parents&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"div.inline-group"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"input"&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]).&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;increment_form_ids&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;ready&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;add_inline_button&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;To facilitate the addition and removal of inlines, Django provides an input field that calculates the total number of forms in the formset. When you insert or remove forms, you need to alter that number so that Django knows to process the data. This is the &lt;em&gt;id_recipe-TOTAL_FORMS&lt;/em&gt; input. Line 24 of the above code increments that value.&lt;/p&gt;
&lt;p&gt;This is based on the work in this blog. &lt;a class="footnote-reference" href="#f2" id="id2"&gt;[2]&lt;/a&gt;&lt;/p&gt;
&lt;div class="success"&gt;
&lt;p&gt;&lt;strong&gt;Sponsored Recipe&lt;/strong&gt;: This recipe was sponsored by &lt;a class="reference external" href="http://www.bluefountain.com/"&gt;Blue Fountain Systems Ltd&lt;/a&gt;. Please contact &lt;a class="reference external" href="http://www.clearwind.ca"&gt;Clearwind&lt;/a&gt; if you’d like to sponsor a recipe.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a class="fn-backref" href="#id1"&gt;[1]&lt;/a&gt; See notes in MEDIA_URL and serving static content, something this recipe does on start up.   &lt;a class="fn-backref" href="#id2"&gt;[2]&lt;/a&gt; &lt;a class="reference external" href="http://www.arnebrodowski.de/blog/507-Add-and-remove-Django-Admin-Inlines-with-JavaScript.html"&gt;&lt;a href="http://www.arnebrodowski.de/blog/507-Add-and-remove-Django-Admin-Inlines-with-JavaScript.html"&gt;http://www.arnebrodowski.de/blog/507-Add-and-remove-Django-Admin-Inlines-with-JavaScript.html&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;</description><link>http://djangozen.com/post/14347123369</link><guid>http://djangozen.com/post/14347123369</guid><pubDate>Sat, 17 Dec 2011 03:12:00 -0500</pubDate></item><item><title>Setting up inline forms in contrib.admin</title><description>&lt;p&gt;&lt;strong&gt;This recipe covers how to set up inline forms in contrib admin and how to show foreign keys in those inline forms.&lt;/strong&gt;&lt;/p&gt;
&lt;div class="section" id="how-to-setting-up-inline-forms-in-contrib-admin"&gt;
&lt;div class="notice"&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: this is excerpt a recipe from cleardjango. You can download the &lt;a href="http://code.google.com/p/cleardjango/source/checkout"&gt;source from SVN&lt;/a&gt;. Once you’ve checked it out, do: &lt;span class="pre"&gt;python&lt;/span&gt; &lt;span class="pre"&gt;tools/configure.py&lt;/span&gt; &lt;span class="pre"&gt;-s&lt;/span&gt; &lt;span class="pre"&gt;70&lt;/span&gt; to install and run this recipe.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;Two different models are often used, one related to another. These are normally shown to users in the Django interface as two separate pages. You could however set up one form that contains the forms for the other model so they can be edited inline. It’s probably simpler to show a quick graphic to demonstrate this:&lt;/p&gt;
&lt;img alt="null" src="http://cleardjango.googlecode.com/svn/trunk/text/media/recipe_70.jpg"/&gt;&lt;p&gt;In this case we’ve got a recipe, a “Cucumber-Rosemary Gin and Tonic” &lt;a class="footnote-reference" href="#f1" id="id1"&gt;[1]&lt;/a&gt; and some ingredients. Let’s take a look at the two models that setup this relationship:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.db&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TextField&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;__unicode__&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;amount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CharField&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;255&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    
    &lt;span class="n"&gt;recipe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;related_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"recipe"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;other_recipe&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;models&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ForeignKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;related_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"other_recipe"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;blank&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;null&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The Ingredient model is slightly unusual because it has two keys pointing back to the recipe. The &lt;em&gt;recipe&lt;/em&gt; field points to the Recipe model. However, some drinks may contain ingredients which are another recipe. There’s no point in covering how to make the recipe every time. Instead this is pointed to once and a reference made. Here it’s just a normal Gin and Tonic with some additions. This pointer to another recipe is the &lt;em&gt;other_recipe&lt;/em&gt; field and is optional.&lt;/p&gt;
&lt;p&gt;So next we’ll need to register these models in the Django admin. We’ll do this in the usual way. For example, in &lt;em&gt;admins.py&lt;/em&gt; we’ll have:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RecipeAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IngredientAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The admin registration for a Recipe is a little different because we need to have this show the ingredient inline. Here we’ll use the contrib.admin inlines functionality &lt;a class="footnote-reference" href="#f2" id="id2"&gt;[2]&lt;/a&gt;. This requires modifying the &lt;em&gt;admins.py&lt;/em&gt; and registering the Recipe slightly differently. Next we’ll use the &lt;em&gt;inlines&lt;/em&gt; attribute on Recipes. This tells the admin interface what inline classes to use. Multiple inlines can be defined but in our case we only need one.&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecipeAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelAdmin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;inlines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;IngredientInline&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;list_display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;IngredientInline&lt;/em&gt; class referred to is a class used to define what will be shown. This looks like:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IngredientInline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TabularInline&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Ingredient&lt;/span&gt;
    &lt;span class="n"&gt;fk_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"recipe"&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Now the code should be ready to run and play with.  We’ve specified a &lt;em&gt;fk_name&lt;/em&gt; on line 3 of the &lt;em&gt;IngredientInline&lt;/em&gt;. That’s the foreign key that contains the relationship back to the recipe. There’s no reason for this to be set in a form since Django will automatically set this to the recipe you are adding or editing. The explicit definition of &lt;em&gt;fk_name&lt;/em&gt; is only necessary in cases where there are &lt;strong&gt;more than one&lt;/strong&gt; foreign key relationships back to the parent model &lt;a class="footnote-reference" href="#f3" id="id3"&gt;[3]&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’d like to make one additional optimization to this form. We have a recipe “Cucumber-Rosemary Gin and Tonic” that contains a reference to another recipe, “Gin and Tonic”. But it could never contain a reference to itself. An ingredient of “Cucumber-Rosemary Gin and Tonic” cannot ever be itself. Recursion is cool for acronyms of open source projects but less cool in the world of cocktails.&lt;/p&gt;
&lt;p&gt;If we know the current object, we can use the queryset api to return all recipes excluding all the current object. If the current object is &lt;em&gt;instance&lt;/em&gt; that would look like this:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt; &lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The harder part is altering the form to do this. There a few different approaches and one is to create a custom form &lt;a class="footnote-reference" href="#f4" id="id4"&gt;[4]&lt;/a&gt;. I chose a slightly different way &lt;strong&gt;because this allows us to work the same way with inlines outside of the admin in later recipes&lt;/strong&gt;. When the admin creates a formset, it calls a method called &lt;em&gt;get_formset&lt;/em&gt; We can pass a number of parameters into that. One of them is a &lt;em&gt;formfield_callback&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;When each form field is rendered, this method will be called so that we can alter each field in the form. Here’s how that callback would look given an instance. It’s called for each and every field so we need to check the field name before altering:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Recipe&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;ingredient_form_callback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"other_recipe"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;formfield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;queryset&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;objects&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;exclude&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;instance&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pk&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;field&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;formfield&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kw&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;We’re almost there but there’s one last thing. The instance isn’t normally passed to the field. We need to add the instance. This can be done quickly and easily by using the django curry method &lt;a class="footnote-reference" href="#f5" id="id5"&gt;[5]&lt;/a&gt;. The entire &lt;em&gt;admin.py&lt;/em&gt; will look like this:&lt;/p&gt;
&lt;div class="highlight-python"&gt;
&lt;div class="highlight"&gt;
&lt;pre&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.contrib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;admin&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;django.utils.functional&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;curry&lt;/span&gt;

&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;models&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Ingredient&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;forms&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;ingredient_form_callback&lt;/span&gt;
    
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IngredientInline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TabularInline&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Ingredient&lt;/span&gt;
    &lt;span class="n"&gt;fk_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"recipe"&lt;/span&gt;

    &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;get_formset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"formfield_callback"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;curry&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ingredient_form_callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nb"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IngredientInline&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="bp"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_formset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;kwargs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;IngredientAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelAdmin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;pass&lt;/span&gt;
        
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RecipeAdmin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ModelAdmin&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;inlines&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="n"&gt;IngredientInline&lt;/span&gt;
    &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;list_display&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;,)&lt;/span&gt;

&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Recipe&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RecipeAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;admin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;register&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Ingredient&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IngredientAdmin&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The end result is pretty cool. We have a Recipe form with inlines below it and a custom form on those inline forms to limit the valid data. As for the virtues of these drinks, feel free to take part in some exhaustive research.&lt;/p&gt;
&lt;div class="success"&gt;
&lt;p&gt;&lt;strong&gt;Sponsored Recipe&lt;/strong&gt;: This recipe was sponsored by &lt;a class="reference external" href="http://www.bluefountain.com/"&gt;Blue Fountain Systems Ltd&lt;/a&gt;. Please contact &lt;a class="reference external" href="http://www.clearwind.ca"&gt;Clearwind&lt;/a&gt; if you’d like to sponsor a recipe.&lt;/p&gt;
&lt;/div&gt;
&lt;a class="fn-backref" href="#id1"&gt;[1]&lt;/a&gt; &lt;a class="reference external" href="http://www.drinksmixer.com/drinkf164e99.html"&gt;&lt;a href="http://www.drinksmixer.com/drinkf164e99.html"&gt;http://www.drinksmixer.com/drinkf164e99.html&lt;/a&gt;&lt;/a&gt; &lt;a class="fn-backref" href="#id2"&gt;[2]&lt;/a&gt; &lt;a class="reference external" href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects"&gt;&lt;a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects"&gt;http://docs.djangoproject.com/en/dev/ref/contrib/admin/#inlinemodeladmin-objects&lt;/a&gt;&lt;/a&gt; &lt;a class="fn-backref" href="#id3"&gt;[3]&lt;/a&gt; &lt;a class="reference external" href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#fk-name"&gt;&lt;a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#fk-name"&gt;http://docs.djangoproject.com/en/dev/ref/contrib/admin/#fk-name&lt;/a&gt;&lt;/a&gt; &lt;a class="fn-backref" href="#id4"&gt;[4]&lt;/a&gt; &lt;a class="reference external" href="http://www.artfulcode.net/articles/runtime-choicefield-filtering-in-djangos-admin/"&gt;&lt;a href="http://www.artfulcode.net/articles/runtime-choicefield-filtering-in-djangos-admin/"&gt;http://www.artfulcode.net/articles/runtime-choicefield-filtering-in-djangos-admin/&lt;/a&gt;&lt;/a&gt; &lt;a class="fn-backref" href="#id5"&gt;[5]&lt;/a&gt; &lt;a class="reference external" href="http://code.djangoproject.com/browser/django/trunk/django/utils/functional.py#L53"&gt;&lt;a href="http://code.djangoproject.com/browser/django/trunk/django/utils/functional.py#L53"&gt;http://code.djangoproject.com/browser/django/trunk/django/utils/functional.py#L53&lt;/a&gt;&lt;/a&gt;&lt;/div&gt;</description><link>http://djangozen.com/post/14347102851</link><guid>http://djangozen.com/post/14347102851</guid><pubDate>Sat, 17 Dec 2011 03:11:00 -0500</pubDate></item><item><title>Tuning the count method on a queryset</title><description>&lt;p&gt;&lt;strong&gt;Some alternate ways to manipulate the pagination of Django query sets.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The other week I faced a real slow down on &lt;a class="external-link" href="http://www.areciboapp.com"&gt;Arecibo&lt;/a&gt; due to a high number of errors being generated by a few other sites. At the time I started to find out how bad Postgres is compared to MySQL in terms of performance when doing a SQL count. MySQL does &lt;a class="external-link" href="http://www.wikivs.com/wiki/MySQL_vs_PostgreSQL#COUNT.28.2A.29"&gt;more work to make that faster&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In Arecibo, we present a list of all the errors that have recently occured. This page is paginated using the &lt;a class="external-link" href="http://www.djangoproject.com/documentation/models/pagination/"&gt;Django pagination&lt;/a&gt; class. To figure out how big the result set is and hence how many pages you have,  the default pagination class will call the method &lt;em&gt;count&lt;/em&gt; on the queryset.&lt;/p&gt;
&lt;p&gt;So how can we make this faster, the first obvious strategy, change count on your query set. To do this write a custom object manager and then create your own count. For example:&lt;/p&gt;
&lt;pre&gt;def count(self):
    # rather stupid count
    return 999999
&lt;/pre&gt;
&lt;p&gt;Hmm that actually works pretty well on some larger Arecibo error pages, because we don’t really need to do a count if you’ve got a lot of results. If you do this, then the pagination class just thinks the list is big and the user sees lots of “next” links.&lt;/p&gt;
&lt;p&gt;How about caching it? That’s straightforward too.&lt;/p&gt;
&lt;pre&gt;def count(self):
    # not fully tested
    if cache.get("count", None):
        return cache["count"]
    count = self.get_query_set().count()
    cache.set("count", count)
    return count
&lt;/pre&gt;
&lt;p&gt;Hmm again, ok. The problem is that this is fast on the second hit. The first hit is slow.&lt;/p&gt;
&lt;p&gt;But you’ve got the general idea. The problem with these is that they change the &lt;em&gt;ObjectManager&lt;/em&gt; and hence the change all count calls for that model (unless I start having multiple ObjectManagers). Actually for me that’s a problem in my application. I still want the django-admin and other parts of the site to work and this change broke quite a lot of unit tests as I quickly looked for a solution.&lt;/p&gt;
&lt;p&gt;You could also overwrite count on a per query set basis. Since there was on key view in Arecibo that was causing the problem, I focused on that and wrote the following:&lt;/p&gt;
&lt;pre&gt;class CountProxy:
    def __call__(self):
        # do something clever here, cache, guess etc
        # to create a count
        return count
&lt;/pre&gt;
&lt;p&gt;Next in your view, assign the CountProxy to the object.&lt;/p&gt;
&lt;pre&gt;queryset = Error.objects.filter(...)
queryset.count = CountProxy()
Paginator(queryset, ...)
&lt;/pre&gt;
&lt;p&gt;In the end my &lt;em&gt;CountProxy&lt;/em&gt; class got quite complicated as it did work to cache and optimise the query based on the filtering. The nice thing is that you have an opportunity to make count as complex and as custom you’d like at this point. Add in some Postgres index tuning and things turned out a lot better. The end result was that I got page that was taking sometimes around 8 seconds (it was a bad day), down to about 40ms.&lt;/p&gt;
&lt;p&gt;The ability to do fine grained control on that &lt;em&gt;count&lt;/em&gt; can be quite useful.&lt;/p&gt;</description><link>http://djangozen.com/post/14347081995</link><guid>http://djangozen.com/post/14347081995</guid><pubDate>Sat, 17 Dec 2011 03:10:23 -0500</pubDate></item><item><title>The lack of magic in Django</title><description>&lt;p&gt;&lt;strong&gt;…or why Rails and Zope 2 were too magical.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There’s been a bit of a discussion recently &lt;a class="external-link" href="http://www.b-list.org/weblog/2009/jul/23/magic/"&gt;about magic&lt;/a&gt; from James Bennett and others. Also one of my friends recently had a play with Ruby and came to &lt;a class="external-link" href="http://regebro.wordpress.com/2009/07/12/python-vs-ruby/"&gt;some conclusions&lt;/a&gt;. I did a bit of work in Rails a while back and it never did much for me I found large applications confusing and hard to debug.&lt;/p&gt;
&lt;p&gt;If you ask me why I don’t like Rails, there’s a simple answer: &lt;strong&gt;it has too much magic&lt;/strong&gt;. &lt;/p&gt;
&lt;p&gt;We all know the quote about technology being indistinguishable from magic. In that law Arthur C. Clarke is describing how a lack of some basic underlying principles means that observers are unable to determine how things work and they seem magical. The same thing can happen in software, something happens when the following peice of code happens. But something magic has happened to make it do so and it’s not obvious to the person developing the software because they are lacking some underlying peice of knowledge.&lt;/p&gt;
&lt;p&gt;Now we can say simply that I didn’t understand all of Rails and hence I was missing knowledge and hence it was all magic. I think that would be wrong, whilst I never got completely to grips with all of Rails, I knew the key parts well enough to be able to produce projects that worked. The test for this is reading someone else’s code and applications and trying to figure out what’s happenening and that’s where Rails (and to a small extent Ruby) do magic to solve a problem.&lt;/p&gt;
&lt;p&gt;Let’s start with an example. Django has explicit models that declare the types of fields a model has. For example here’s a Django model:&lt;/p&gt;
&lt;pre&gt;class Poll(models.Model):
    question = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')&lt;/pre&gt;
&lt;p&gt;Django (optionally) creates the SQL from your model and populates the database with it. Here’s a model from Rails.&lt;/p&gt;
&lt;pre&gt;class Post &lt; ActiveRecord::Base
end&lt;/pre&gt;
&lt;p&gt;The schema is declared in a migration.&lt;/p&gt;
&lt;pre&gt;class CreatePosts &lt; ActiveRecord::Migration
  def self.up
    create_table :posts do |t|
      t.string :name
      t.string :title
      [...snipped]&lt;/pre&gt;
&lt;p&gt;In Rails you write the migration, the schema is created in the database and Rails infers from the database your model (don’t forget Rails will rename your table and try to pluralize it for, thanks Rails).&lt;/p&gt;
&lt;p&gt;Now let’s take a scenario where you are working on a project that has over 200 migrations. To tell what’s in your model, you either a) wade through all the migrations that are relevant to your model or b) keep examining your database. It’s not that point b) is bad, it’s important to know what’s going on in your database.&lt;/p&gt;
&lt;blockquote&gt;Explicit is better than implicit&lt;/blockquote&gt;
&lt;p&gt;In Django I’m explicitly saying what fields I’m expecting on a model, what they are and what they manage. I’m also declaring the methods and attributes on an object - or a namespace. I know what at a glance Poll.question (Django) is, figuring out what Post.name (Rails) isn’t as obvious. Indeed there’s nothing stopping me adding a method to the Post class called name.  &lt;span class="Apple-style-span"&gt;Rails is doing a looking up for you on the object to calculate the variable. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="Apple-style-span"&gt;But it’s doing more than that. For example:&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;class Sample &lt; ActiveRecord::Base
    def wtf
        foo
    end
end&lt;/pre&gt;
&lt;p&gt;What does Sample.wtf give you? Does the method &lt;em&gt;foo &lt;/em&gt;exist on the object (and presumably in the inheritance tree), does the method &lt;em&gt;foo &lt;/em&gt;exist somewhere else in the namespace, does anything else import &lt;em&gt;foo &lt;/em&gt;into the global namespace, does &lt;em&gt;foo &lt;/em&gt;exist on the database for that model?&lt;/p&gt;
&lt;p&gt;To me this is not explicit and hence somewhat &lt;strong&gt;magical&lt;/strong&gt;. That is my definition of magical, something is going to happen that is not obvious or clear. There’s some implicit assumption that you know a whole bunch more information about the code and the context it’s being run in.&lt;/p&gt;
&lt;p&gt;As a developer reading this you have to do all that work to figure out what &lt;em&gt;foo&lt;/em&gt; is, or do runtime analysis. To me this flies in the face of another rule:&lt;/p&gt;
&lt;blockquote&gt;In the face of ambiguity, refuse the temptation to guess.&lt;/blockquote&gt;
&lt;div&gt;Rails developers may call &lt;a class="external-link" href="http://ruby.brian-amberg.de/editierdistanz/"&gt;not defining the namespace DRY&lt;/a&gt;, but I call it laziness and ambiguity. &lt;/div&gt;
&lt;blockquote&gt;Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it.&lt;/blockquote&gt;
&lt;p&gt;This philosophy goes on through Rails in many different areas, here’s some &lt;a href="http://nathany.com/developer/rails-magic/"&gt;more examples&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Let’s look at Zope 2 for a minute and Acquisition and DTML. Alright I’m picking at pieces that either no longer exist or are now explicit, but that’s because the developers found way too many issues with the said technologies. Learning from past mistakes and not repeating them is an important thing to be able to do.&lt;/p&gt;
&lt;p&gt;In Zope 2 there was a templating language called DTML that you could write on objects. When it was rendered it would act on the object in the database and then use Acquisition to figure out what to do next. Acquisition can be &lt;a class="external-link" href="http://207.22.26.166/bytecols/2001-06-13.html"&gt;pretty&lt;/a&gt; &lt;a class="external-link" href="http://www.zope.org/Members/crazybrett/acquisition"&gt;mind&lt;/a&gt; bending, it doesn’t mean it was wrong, but to many developers it was just far too magical.&lt;/p&gt;
&lt;p&gt;Code that worked in one place, wouldn’t work in another because the context it was being executed in wasn’t right. Not in itself wrong, but &lt;em&gt;very hard&lt;/em&gt; to figure out and debug so to many it became magical. Never mind the confusing syntax which differentiated between: &lt;/p&gt;
&lt;p&gt;&lt;dtml-var foo&gt;, &lt;dtml-var “foo”&gt; and &lt;dtml-var “_.foo”&gt;&lt;/p&gt;
&lt;p&gt;I have to confess I don’t have any concrete examples of this since all that code has long since vanished into a distant past, but I wanted to point out that it’s not just Rails. Training developers in this was great fun, the principle was all well and good, but all too often I saw people resort to random guessing of code to get it working.&lt;/p&gt;
&lt;p&gt;Technology is thought of as magical because something is happening that we don’t understand. Frameworks that make decisions for you at runtime based on things you haven’t explicitly declared can be seen as performing some magic. The level of magic has inverse relationship to the level of explicitness. Django is more explicit and much less magical. Rails is less explicit and rather magical. Zope 2 was very magical.&lt;/p&gt;
&lt;p&gt;&lt;span class="Apple-style-span"&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;BTW: &lt;span class="Apple-style-span"&gt;Yes, I’m quoting the Zen of Python, by Tim Peters. To read the whole thing start your Python and type “import this”. &lt;/span&gt;&lt;/p&gt;</description><link>http://djangozen.com/post/14347052244</link><guid>http://djangozen.com/post/14347052244</guid><pubDate>Sat, 17 Dec 2011 03:08:50 -0500</pubDate></item><item><title>Forms, forms, forms</title><description>&lt;p&gt;&lt;strong&gt;Some questions answered about Django forms.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;…again based on questions that keep cropping up in the IRC channels.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;1. How do I add or change fields on a ModelForm?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The exact same way you do on a normal Form. If the name of the field matches a field that already exists on the model the form is using, it will override the default.&lt;/p&gt;
&lt;pre&gt;class Cool(forms.ModelForm):
    new = forms.CharField()
    class Meta:
        model = User&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. If I add fields to a ModelForm, the data in those fields does not get saved.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No, they won’t, because they aren’t attached to the model, so you would have to save them manually.&lt;/p&gt;
&lt;p&gt;&lt;span class="Apple-style-span"&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. Can one model form have more than one model?&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;No.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4. But my form is quite complicated….&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Remember the following:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Django forms are about data validation&lt;/li&gt;
&lt;li&gt;… they just happen to also render themselves nicely as some HTML&lt;/li&gt;
&lt;li&gt;a ModelForm is a form for one and &lt;em&gt;only one&lt;/em&gt; model&lt;/li&gt;
&lt;li&gt;a Form is not bound to a model and can be any number of fields&lt;/li&gt;
&lt;li&gt;a HTML Form can contain &lt;em&gt;any number&lt;/em&gt; of Form or ModelForm instance&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;So for example, if you make a User Profile, you might have one HTML page to edit user details like email address (in the User model) and Facebook account (in the User Profile model). To do this:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Make two ModelForms, one for each model. &lt;/li&gt;
&lt;li&gt;Pass both through to the view, have both render on the same template. &lt;/li&gt;
&lt;li&gt;The template will look something like this:&lt;/li&gt;
&lt;/ul&gt;&lt;pre&gt;&lt;form&gt;
{{ form_one }}
{{ form_two }}
&lt;/form&gt;&lt;/pre&gt;
&lt;ul&gt;&lt;li&gt;When the form is submitted, all you have to do is check the two forms are valid, something like:&lt;/li&gt;
&lt;/ul&gt;&lt;pre&gt;if form_one.is_valid() and form_two.is_valid():
    form_one.save()
    form_two.save()&lt;/pre&gt;
&lt;p&gt;Although the names are similar, a HTML Form and a Django Form are quite different.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Update:&lt;/em&gt; Sep 2009, improving some of the grammar and erm words.&lt;/p&gt;</description><link>http://djangozen.com/post/14347022175</link><guid>http://djangozen.com/post/14347022175</guid><pubDate>Sat, 17 Dec 2011 03:07:13 -0500</pubDate></item><item><title>Features of a good Django plugin</title><description>&lt;p&gt;&lt;strong&gt;Well, my opinion on them anyway.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A while back I wanted to allow openid logins on my site. A simple problem which a few plugins released to the Django community make easier. However there’s quite a few of them (&lt;a class="external-link" href="http://djangozen.com/search/?q=openid"&gt;we list 4&lt;/a&gt;, there’s more) and none of them quite work the way I want.&lt;/p&gt;
&lt;p&gt;So what’s wrong with them? Most of them define front end templates or particular models or a particular way of doing it. I don’t want that, I just want to make my application do openid authentication. So in frustration I have something which is a complete rip off of django-simple-openid from Benoît Chesneau.&lt;/p&gt;
&lt;p&gt;When I’m building a website I do the following:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Create a user profile that contains custom user information. In this model I’d like to add in my openid information for the user.&lt;/li&gt;
&lt;li&gt;Create an authentication backend that looks up the user profile defined before and logs the user in.&lt;/li&gt;
&lt;li&gt;Create custom login, join, signout pages.&lt;/li&gt;
&lt;li&gt;Create some middleware.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;If I’m going to create all these steps I want a plugin that fits into this pattern. A lot of them end up being like&lt;em&gt; contrib.comments&lt;/em&gt;, something you have to fight to get customised. As an example, here’s what I would like to see in an openid plugin:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Let me define my openid field on a model and make that a profile (standard Django practice)&lt;/li&gt;
&lt;li&gt;Let me write my custom authentication backend (standard Django practice)&lt;/li&gt;
&lt;li&gt;Document that I need to do the following views: login, login failed and signout and tell me the API to call&lt;/li&gt;
&lt;li&gt;Document the data I need in forms to pass to the views&lt;/li&gt;
&lt;li&gt;Provide an &lt;em&gt;example&lt;/em&gt; set of models, views and template that I can choose to ignore&lt;/li&gt;
&lt;li&gt;Let me write my own views and template (standard Django practice)&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Thinking about it this mirrors the general Django philosophy in many ways. Perhaps a list for what a plugin should have:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;No front end user interface&lt;/li&gt;
&lt;li&gt;No standard models, just example models&lt;/li&gt;
&lt;li&gt;No standard views, just example views&lt;/li&gt;
&lt;li&gt;Unit tests&lt;/li&gt;
&lt;li&gt;Documentation&lt;/li&gt;
&lt;li&gt;An example implementation&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The primary job of someone using your plugin is to integrate it with their application. Let’s make that a bit easier. &lt;/p&gt;
&lt;p&gt;&lt;em&gt;Disclaimer:&lt;/em&gt; the new openid implementation from Simon Willison looks great. Although it does look worryingly complex, it seems to (at my quick glances over the code) accomplish the above.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Other disclaimer:&lt;/em&gt; it’s easy to say this standing up on my ivory tower since I haven’t actually released my openid library, because its a hacked up mess. Chances are as soon as I write about this, someone will come along and point out their Django openid plugin which does it just the way I want. I hope so.&lt;/p&gt;</description><link>http://djangozen.com/post/14347005156</link><guid>http://djangozen.com/post/14347005156</guid><pubDate>Sat, 17 Dec 2011 03:06:20 -0500</pubDate></item><item><title>Read only fields in models</title><description>&lt;p&gt;&lt;strong&gt;Supposing you have a field in your model and you don’t want it to be changed, ever.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;How would you do that? Well actually you can’t from Django, which we’ll see in a minute. Here’s a script that should work for most people. Basically, set up a signal (or a custom save method) so that when your object is saved it compares the old to new and then figures out if it can be changed.&lt;/p&gt;
&lt;pre&gt;from django.db import models

class BankAccount(models.Model):
    amount = models.DecimalField(max_digits=20, decimal_places=2)
    number = models.CharField(max_length=10)
    
    read_only = ("number",)
        
def read_only(sender, instance, **kw):
    if instance.id:
        old = sender.objects.get(id=instance.id)
        for field in sender.read_only:
            if (getattr(old, field) != getattr(instance, field)):
                raise ValueError, "The field %s cannot be changed, once set, ever." % field

models.signals.pre_save.connect(read_only, sender=BankAccount)&lt;/pre&gt;
&lt;p&gt;On a save, we look up the read_only attribute and see if any of those fields have changed and raise an error if they do. In this scenario, you can change the amount of money in a bank account, but the number of the account will not change once set.&lt;/p&gt;
&lt;p&gt;Here’s a test to check it works:&lt;/p&gt;
&lt;pre&gt;from django.test import TestCase                
from models import BankAccount
from decimal import Decimal

class tests(TestCase):
    def testReadOnly(self):
        bank = BankAccount()
        bank.number = "1234567890"
        bank.amount = Decimal("100.00")
        bank.save()
        
        id = bank.id
        
        bank.amount = Decimal("200.00")
        bank.save()
        
        bank.number = "9999999999"
        self.assertRaises(ValueError, bank.save)&lt;/pre&gt;
&lt;p&gt;This is awfully close to model validation. Something that Django doesn’t have yet. And it there’s two areas it can break down.&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;When someone writes raw SQL.&lt;/li&gt;
&lt;li&gt;The update method on a QuerySet &lt;strong&gt;does not call the signal or the custom save&lt;/strong&gt; method. For example:&lt;/li&gt;
&lt;/ul&gt;&lt;pre&gt;        # Warning does not work with update
        BankAccount.objects.all().update(number="999999999")
        # eeek!
        assert BankAccount.objects.get(id=id).number == "999999999"&lt;/pre&gt;

&lt;p&gt;This is discussed &lt;a class="external-link" href="http://code.djangoproject.com/ticket/7447"&gt;here&lt;/a&gt; and &lt;a class="external-link" href="http://code.djangoproject.com/ticket/6915"&gt;here&lt;/a&gt;. I wonder if it’s worth going any further on this until model validation comes along. Perhaps not.&lt;/p&gt;</description><link>http://djangozen.com/post/14346972291</link><guid>http://djangozen.com/post/14346972291</guid><pubDate>Sat, 17 Dec 2011 03:04:38 -0500</pubDate></item><item><title>Class based views</title><description>&lt;p&gt;&lt;strong&gt;We discussed these at a recent Vancouver Django (May 2009) meetup and it was also a pattern I used on a recent project.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Traditionally in Django a URL points to a function. So something like this is probably what you familar with:&lt;/p&gt;
&lt;pre&gt;from django.conf.urls.defaults import patterns

urlpatterns = patterns('',
    (r'^hello-function/$', 'recipe_9.views.hello_function')
)&lt;/pre&gt;
&lt;p&gt;And a view that looks like this:&lt;/p&gt;
&lt;pre&gt;from django.http import HttpResponse
        
def hello_function(request):
    return HttpResponse("Hello world!")&lt;/pre&gt;
&lt;p&gt;As it turns out, Django only needs something that is callable, so this can be a class. Let’s just show the difference. The URLs:&lt;/p&gt;
&lt;pre&gt;from django.conf.urls.defaults import patterns
from views import hello_class

urlpatterns = patterns('',
    (r'^hello-class/$', hello_class()),
)&lt;/pre&gt;
&lt;p&gt;The class:&lt;/p&gt;
&lt;pre&gt;from django.http import HttpResponse

class hello_class:
    def __call__(self, request):
        return HttpResponse("Hello world!")&lt;/pre&gt;
&lt;p&gt;Oh and let’s not forget some tests to prove this works:&lt;/p&gt;
&lt;pre&gt;from django.test import TestCase                
from django.test.client import Client

class tests(TestCase):
    def testFunction(self):
        clt = Client()
        res = clt.get("/hello-function/")
        assert res.status_code == 200
        assert res.content == 'Hello world!'
        
    def testClass(self):
        clt = Client()
        res = clt.get("/hello-class/")
        assert res.status_code == 200
        assert res.content == 'Hello world!'&lt;/pre&gt;
&lt;p&gt;What’s the advantage of this? Well since it’s a class you get all the advantages of being a class, doing things on the __init__, subclassing, overriding the __call__ and so on. Let’s take an example. An extension of the &lt;a class="external-link" href="http://djangozen.com/blog/11-days-in-kenya"&gt;Kenyan project&lt;/a&gt; for me recently was a similar project in another country. Similar, but of course, not the same. There were differences in the text and how certain situation are handled. So I made all the views point to classes (at this point I will add I also altered our URLResolver)… anyway all the requests in these projects do that same thing:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;parse the user input into a form&lt;/li&gt;
&lt;li&gt;validate the user input&lt;/li&gt;
&lt;li&gt;process it&lt;/li&gt;
&lt;li&gt;return an response&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;This logic of processing the request in this order has been pushed into a class. All my views inherit from it. So now the code for country X only deals with the specific parts for that country. When I add country Z to the mix, I just need to change the specific parts for that country.&lt;/p&gt;
&lt;p&gt;Whilst this may sound a bit specialised, many applications can use this. For example one of the first applications I have takes every request and then checks the account information on that request (it doesn’t use session for other reasons). So the first line of every view is a call to go and get that information. Making a part of template request processor sort of works, but you have to do work to dig that back out.&lt;/p&gt;
&lt;p&gt;In the end making it a class based view adds only about 3 lines of code but makes you app much more reusable and adaptable in the future.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a class="external-link" href="http://www.slideshare.net/simon/django-heresies"&gt;Simon Willison in his talk at EuroDjangoCon 2009&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><link>http://djangozen.com/post/14346915942</link><guid>http://djangozen.com/post/14346915942</guid><pubDate>Sat, 17 Dec 2011 03:01:54 -0500</pubDate></item><item><title>Useful Django API's</title><description>&lt;p&gt;&lt;strong&gt;Two useful Django API’s that I’ve found today.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="Apple-style-span"&gt;Model to Dict&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;A useful little fella hiding away in the forms module. Ever want a dictionary of your model and it’s fields? Then this one will give you that. Useful for mapping a model into a big string. For example in a recent project we are sending a message about the facility.. pass in a facility into a string and you’ll get:&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; "%(id)s" % facility
Traceback (most recent call last):
  File "&lt;console&gt;", line 1, in &lt;module&gt;
TypeError: 'Facility' object is unsubscriptable&lt;/pre&gt;
&lt;div&gt;&lt;span class="Apple-style-span"&gt;But with add in a model_to_dict call and you’ll get back a dictionary suitable for mapping:&lt;/span&gt;&lt;/div&gt;
&lt;pre&gt;from django.forms.models import model_to_dict
&gt;&gt;&gt; "%(id)s" % model_to_dict(facility)
'1'&lt;/pre&gt;
&lt;h3&gt;Finding models&lt;/h3&gt;
&lt;p&gt;This one requires a few assumptions. Supposing you want to find an model called Log in your project. You don’t care what the model is, what application it is in, just that there is something called Log. We would presume that Log had all the appropriate API and made sense in the project. &lt;/p&gt;
&lt;p&gt;In my scenario, I need to find the table name of log, so that I can run some custom, raw sql on it. I did not want to hardcode the table name. So I needed to find log, to access the db_table. The class &lt;span class="Apple-style-span"&gt;from django.db.models.loading import AppCache provides some very useful stuff.&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;from django.db.models.loading import AppCache

class _models:
    def __init__(self):
        app = AppCache()
        for m in app.get_models():
            setattr(self, m.__name__, m)

models = _models()&lt;/pre&gt;
&lt;p&gt;This creates a instance models that contains a pointer to the model definitions. I called this resolve.py, sounded like a reasonable name. So now I can do:&gt;&lt;/p&gt;
&lt;pre&gt;&gt;&gt;&gt; from resolve import models
&gt;&gt;&gt; models.Log
&lt;class 'apps.sms.models.base.Log'&gt;&lt;/pre&gt;
&lt;div&gt;And I’ve got the Log, regardless of where it came from.&lt;/div&gt;</description><link>http://djangozen.com/post/14346886214</link><guid>http://djangozen.com/post/14346886214</guid><pubDate>Sat, 17 Dec 2011 03:00:31 -0500</pubDate></item><item><title>Caching and signals</title><description>&lt;p&gt;&lt;strong&gt;Adding in cached objects on signals.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Was reading this &lt;a class="external-link" href="http://immike.net/files/scaling_django.pdf"&gt;great talk on Django and performance&lt;/a&gt; from EuroDjangoCon. There are some good points in there, one I wanted to play with quickly was the caching framework and signals. &lt;/p&gt;
&lt;p&gt;I’m a big fan of signals and the idea of setting and deleting the cache as objects change was just something I had to quickly play with. Nothing too revolutionary here, but it simply sets and gets the cache when the object changes.&lt;/p&gt;
&lt;pre&gt;from django.db import models
from django.core.cache import cache
from django.db.models.signals import post_save, post_delete

def _key(model, id):
    return "%s.%s" % (model.__name__, id)

class Car(models.Model):
    make = models.CharField(max_length=255)
    
    def key(self):
        return _key(self.__class__, self.pk)

def create_cache(sender, **kw):
    cache.set(kw["instance"].key(), kw["instance"])

def delete_cache(sender, **kw):
    cache.delete(kw["instance"].key())

post_save.connect(create_cache, sender=Car)
post_delete.connect(delete_cache, sender=Car)&lt;/pre&gt;
&lt;p&gt;So each time the object is created or deleted, the cache gets updated (and thanks to being signals, simple to reuse for any class). And here’s a test case.&lt;/p&gt;
&lt;pre&gt;from django.test import TestCase
from django.core.cache import cache
from models import Car

class CacheTest(TestCase):
    def setUp(self):
        car = Car()
        car.make = "Avensis"
        car.save()
        
        self.car = car
        self.id = car.pk
        
    def testCar(self):
        key = self.car.key()
         
        assert cache.has_key(key)
        assert cache.get(key).make == "Avensis"
        
        self.car.make = "Auris"
        assert cache.get(key).make == "Avensis"
        self.car.save()
        assert cache.get(key).make == "Auris"
        
        self.car.delete()
        assert not cache.has_key(key)&lt;/pre&gt;
&lt;p&gt;As an improvement (and indeed the next recipe in my book) it does this through an ObjectManager so that you can just call:&lt;/p&gt;
&lt;pre&gt;Car.objects.cache(id)&lt;/pre&gt;
&lt;p&gt;And get the cached object back, setting the object in the cache if it’s not already there. There are some problems, including possible race conditions, as slide 30 of the presentation does point out. But it’s an interesting start and definitely something I need to play with a bit more.&lt;/p&gt;
&lt;p&gt;References&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a class="external-link" href="http://docs.djangoproject.com/en/dev/topics/cache/#the-low-level-cache-api"&gt;&lt;a href="http://docs.djangoproject.com/en/dev/topics/cache/#the-low-level-cache-api"&gt;http://docs.djangoproject.com/en/dev/topics/cache/#the-low-level-cache-api&lt;/a&gt;&lt;/a&gt; &lt;/li&gt;
&lt;li&gt;&lt;a class="external-link" href="http://immike.net/files/scaling_django.pdf"&gt;Django and perfomance talk&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><link>http://djangozen.com/post/14346844331</link><guid>http://djangozen.com/post/14346844331</guid><pubDate>Sat, 17 Dec 2011 02:58:24 -0500</pubDate></item><item><title>Django, Malnutrition, SMS and Kenya</title><description>&lt;p&gt;&lt;strong&gt;How I ended up doing one of most interesting and important projects I’ve been involved with.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A while back I got home from dinner to find a quick Skype chat from a friend, &lt;a class="external-link" href="http://www.nateaune.com/"&gt;Nate Aune&lt;/a&gt; that basically went “you free to go to Kenya to do some Django - oh and you have to leave on Sunday” (that was in about 4 days time). The response was “is this for real?”. But as it turns out it was and about 6 days later I was leaving on a plane to Kenya, to work on a Django project.&lt;/p&gt;
&lt;p&gt;The person behind this project is &lt;a class="external-link" href="http://twitter.com/mberg"&gt;Matt Berg&lt;/a&gt;, who works at &lt;a class="external-link" href="http://www.columbia.edu/"&gt;Columbia University&lt;/a&gt; on the &lt;a class="external-link" href="http://www.earth.columbia.edu/articles/view/1799"&gt;Millennium Villages&lt;/a&gt; project. This particular project was already in the works and was based on excellent work from &lt;a class="external-link" href="http://twitter.com/schuyler"&gt;Schuyler Erle&lt;/a&gt;, I was to provide support on site and add in some new features.&lt;/p&gt;
&lt;p&gt;The goal of this particular Django project is to help health care workers resolve cases of malnutrition (and as it turned out malaria and other diseases) faster and help more children get treatment faster. To do this, the project uses cell phones.&lt;/p&gt;
&lt;p&gt;So when a health care worker using the project finds a child with malnutrition, they enter the details into a their cell phone and send a text message to a phone number. For all you twitterers out there, you will realize we hit the downside, those details entered ideally need to be under 140 chars.&lt;/p&gt;
&lt;p&gt;Set up is a modem listening to that number, it feeds into a Ruby daemon called spomsky which is part of the &lt;a class="external-link" href="http://rapidsms.org/"&gt;RapidSMS&lt;/a&gt; project. That pushes a request over to a RapidSMS project written in Django and that’s where it get’s relevant to this blog.&lt;/p&gt;
&lt;p&gt;RapidSMS is a cool project that “is UNICEF’s open source platform for data collection, 			logistics coordination and communication allowing any mobile 			phone to interact with the web”. You can get the source here: &lt;a class="external-link" href="http://rapidsms.org/"&gt;&lt;a href="http://rapidsms.org/"&gt;http://rapidsms.org/&lt;/a&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Once the message comes in, it hits a Django process, unlike most Django web applications there are two processes running. The first is a RapidSMS process called &lt;em&gt;route &lt;/em&gt;and this is a process that connects to spomsky and listens for text’s coming in. The second is the standard Django &lt;em&gt;runserver&lt;/em&gt; which provides a web interface for managers to see what is going on.&lt;/p&gt;
&lt;p&gt;So the message is evaluated, for example: does this child one of the levels of malnutrition that warrant attention. If it does then we send a message back to the health care worked asking for the child to be sent to the clinic. It will also route messages to the clinic and to the local health care co-ordinator.&lt;/p&gt;
&lt;p&gt;This routing is done using a &lt;a class="external-link" href="http://github.com/unicefinnovation/rapidsms/blob/19bdbb393417a9f5ee5a56b20983c21272ad700b/lib/rapidsms/parsers/keyworder.py"&gt;very clever decorator&lt;/a&gt; that allows you to assign what text message goes to what method, eg:&lt;/p&gt;
&lt;pre&gt; @keyword(r'n(?:ote)? \+(\d+) (.+)')
    @authenticated
    def note_case (self, message, ref_id, note):         
        [...]&lt;/pre&gt;
&lt;p&gt;Sending out a message is a simple in RapidSMS as doing:&lt;/p&gt;
&lt;pre&gt;    message.respond("Thanks")&lt;/pre&gt;
&lt;p&gt;In this example, you can send in a text message that reads (for example):&lt;/p&gt;
&lt;pre&gt;note +12 has malnutrition and needs care now&lt;/pre&gt;
&lt;p&gt;Where +12 is the child’s ID. The + was chosen to signify an ID, because on the particular phones used, the + is easy to get to without hitting too many buttons. Real messages would be more complicated and involve use of a &lt;a class="external-link" href="http://msf.ca/blogs/photos/tag/muac/"&gt;MUAC&lt;/a&gt; measurement for example:&lt;/p&gt;
&lt;pre&gt;muac +26 7.5 2150 1.4 n&lt;/pre&gt;
&lt;p&gt;That rather cryptic text would give you back (new lines added for readability):&lt;/p&gt;
&lt;pre&gt;MUAC&gt; SAM Patient requires OTP care. 
  +26 MADISON, M, F/4 (Sally). 
  MUAC 75 mm, 2.1 kg, 140 cm&lt;/pre&gt;
&lt;p&gt;These responses would go to health care facilitator’s or co-ordinator’s or to the clinics as relevant. Not only then does this give people the notification to follow up and make sure that the children get the treatment, but allows recording of the data.&lt;/p&gt;
&lt;p&gt;On the back end in the office, there’s that second Django process which serves out a front end, that allows them to search, find and get data on the users. As that UI evolves it will let the users look up that data by clinic, district and so on.&lt;/p&gt;
&lt;p&gt;This might sound simple, but for all those incoming messages, we wrote a lot of tests. I’ve done some mission critical code before, but knowing that I could miss a child with a serious medical condition, made me even more paranoid than normal. RapidSMS includes the really nice ability to write tests in a simple way.&lt;/p&gt;
&lt;p&gt;For example here’s an example of an incoming malaria test of a child from phone number 7654321 (signified by the &gt;). It is then sent to back to the reporter and also to a supervisor at 7654322 (signified by the &lt;)&lt;/p&gt;
&lt;pre&gt;7654321 &gt; mrdt +26 y n f
7654321 &lt; MRDT&gt; Child +26, MADISON, Molly, F/4 has MALARIA. 
    Child is 4. Please provide 2 tabs of Coartem (ACT) 
    twice a day for 3 days
7654322 &lt; MRDT&gt; Child +26, MADISON, Molly, F/4 (None) has MALARIA. 
    CHW: @jdoe 7654321&lt;/pre&gt;
&lt;p&gt;And that’s it. For about 6 days I worked with Matt adding in new features, new forms and new tools for the health care workers. On one day I got the chance to go out into the field and watch the health care workers get trained. It was great to see the health care workers pick this system up quickly and get used to using the system. The first few times sending messages took a little bit of time, but after a while they picked up quickly and really got the hang of the system and really seemed to appreciate it.&lt;/p&gt;
&lt;p&gt;A brief aside here, the use of cell phones for this is absolutely brilliant. In Kenya there are lots and lots of cell phones. I won’t go as far to say everyone has one, but lots do. One image that struck me was a farmer clearing a field and taking a call on his cell phone at the time. Africa skipped the whole “stringing copper wires from poles” step that Western societies took. In Canada on every street corner there’s a Starbucks. In Nairobi it’s a cell phone store or pre-paid top up.&lt;/p&gt;
&lt;p&gt;And that’s it, a few days later I was on a plane back over to Canada (well 4 planes). Leaving some people with the task of driving adoption and training users in the field how to use the project.&lt;/p&gt;
&lt;p&gt;Of all the projects I’ve done, it’s got the potential for being the most important project I’ve done - and that’s really cool. And the real potential of RapidSMS spreads way beyond just this project. The ability to set up a sophisticated distributed system quickly using SMS has so many possible applications. It could great for inventory management, disaster management, anything. With RapidSMS and Django it becomes a real possibility to set this system up quickly. Of course these sorts of systems have existed in the past, but I doubt they have been set up as quickly and easily as RapidSMS allows.&lt;/p&gt;
&lt;p&gt;A big thanks by the way to Matt and &lt;a class="external-link" href="http://twitter.com/jessfanzo"&gt;Jess&lt;/a&gt; and other Millenium Villages people for looking after this muzungu while I was in Africa. Also thanks to Schuyler for doing lots of great work and helping out on RapidSMS, spomsky and git.&lt;/p&gt;
&lt;p&gt;Note: The personal details of getting to Kenya and back and can be found over on my &lt;a class="external-link" href="http://www.agmweb.ca/blog/andy"&gt;personal blog&lt;/a&gt;, the focus here is on the technical side. Further if you looking for details on the efficiency of malnutrition programs or this program in general, I don’t have them either, I don’t know anything about that, Django stuff only.&lt;/p&gt;</description><link>http://djangozen.com/post/14346820283</link><guid>http://djangozen.com/post/14346820283</guid><pubDate>Sat, 17 Dec 2011 02:57:00 -0500</pubDate></item><item><title>Turning off django signals</title><description>&lt;p&gt;&lt;strong&gt;While I’m on the subject, how to turn off signals that you don’t want on.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The first and most obvious signal to turn off is the one asking you for a username and password on syncdb, gosh that’s annoying. You can do this by calling: &lt;/p&gt;
&lt;pre&gt;python manage.py syncdb --noinput&lt;/pre&gt;
&lt;p&gt;But if you want to do this in Python you can:&lt;/p&gt;
&lt;pre&gt;from django.contrib.auth import models as auth_app
from django.contrib.auth.management import create_superuser
from django.db.models.signals import post_syncdb
post_syncdb.disconnect(create_superuser, 
       sender=auth_app, 
       dispatch_uid = "django.contrib.auth.management.create_superuser")&lt;/pre&gt;
&lt;p&gt;The part that was annoying was figuring out just how to get it to disconnect, to find that dispatch_uid I had to go and read the source, not onerous at all. My previous post was about signals vs save. To all that I’ll add an annoyance with signals: if you load in fixtures the, signals get called. This is annoying because I wanted to do the following:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;load in a set of users from fixtures&lt;/li&gt;
&lt;li&gt;load in a set of profiles from fixtures&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Unfortunately all the profiles failed, because the profiles are all created when the users are imported. To solve this on my test or reset scripts I need to turn off the creating a profile signal:&lt;/p&gt;
&lt;pre&gt;from django.db.models.signals import post_save
from django.contrib.auth.models import User
from users.models import create_profile # this is where my signal is registered
post_save.disconnect(create_profile, sender=User)&lt;/pre&gt;
&lt;p&gt;I will chalk that up as definite disadvantage for signals, perhaps there’s a more cunning way around that.&lt;/p&gt;</description><link>http://djangozen.com/post/14346792072</link><guid>http://djangozen.com/post/14346792072</guid><pubDate>Sat, 17 Dec 2011 02:55:49 -0500</pubDate></item><item><title>Signal vs overriding save</title><description>&lt;p&gt;&lt;strong&gt;I’m a big fan of signals and wonder why people are so adverse to using them, preferring overriding save instead.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Probably every day on the Django IRC channel, someone asks about how to set a user on a model or about setting the time automatically. Fortunately thanks to &lt;a class="external-link" href="http://www.b-list.org/weblog/2008/dec/24/admin/"&gt;this excellent article&lt;/a&gt;, we are all familiar with the former. The latter is easy to do as well, without having to resort to using the now deprecated (maybe) &lt;em&gt;auto_now&lt;/em&gt; and &lt;em&gt;auto_now_add&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Here’s how to do it overriding the save:&lt;/p&gt;
&lt;pre&gt;from django.db import models
from datetime import datetime

class Todo(models.Model):
    text = models.CharField(max_length=255)
    completed = models.BooleanField(default=False)
    timestamp = models.DateTimeField()
    
    def save(self, *args, **kw):
        if not self.id:
            self.timestamp = datetime.now()
        super(Todo, self).save(*args, **kw)&lt;/pre&gt;
&lt;p&gt;And here’s how to do it with a signal:&lt;/p&gt;
&lt;pre&gt;from django.db import models
from datetime import datetime

class Todo(models.Model):
    text = models.CharField(max_length=255)
    completed = models.BooleanField(default=False)
    timestamp = models.DateTimeField()
 
def add_date(sender, instance, **kw):
    instance.timestamp = datetime.now()

models.signals.pre_save.connect(add_date, sender=Todo)&lt;/pre&gt;
&lt;p&gt;Setting up a signal is surprisingly easy and one line less of code. Is it more expensive from a CPU point of view? Not really. Here’s a script that ran the two models:&lt;/p&gt;
&lt;pre&gt;from chapter_2.recipe_3.models import Todo
from time import time

start = time()
for x in range(0, 10000):
    todo = Todo()
    todo.text = "Get some milk %s" % x
    todo.save()
    
diff = time() - start
print "Time: %s" % diff&lt;/pre&gt;
&lt;p&gt;Running this with signals:&lt;/p&gt;
&lt;pre&gt;Time: 6.97824287415&lt;/pre&gt;
&lt;p&gt;Running this with save:&lt;/p&gt;
&lt;pre&gt;Time: 6.53473687172&lt;/pre&gt;
&lt;p&gt;I re-ran it a few times and never got a significant difference between the two. Sometimes the signals were faster. I think I can be reasonably sure that signals (in this simple scenario) do not add significant performance cost. So what’s the problem with signals?&lt;/p&gt;
&lt;p&gt;The advantages:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;The signal can be applied to any number of models, without having to repeat override save all over the place. Admittedly in the above example, if you made a base class and override save there, you wouldn’t have the problem.&lt;/li&gt;
&lt;li&gt;Can be applied to models you don’t necessarily have access to or want to modify.&lt;/li&gt;
&lt;li&gt;Overriding methods make me uncomfortable. The &lt;em&gt;save&lt;/em&gt; is pretty obvious, but it’s easy to end up with a model that has a bunch of magic methods. Renaming one of them will cause grief as you are no longer overriding the correct one. And once I forgot to call &lt;em&gt;super&lt;/em&gt; in the save, but that’s just my own incompetence.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;The disadvantage:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;You can end up with a lot of signals and forget what signal occurs when (easier to lose track than lots of save’s in the model inheritance)&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Since creating a new signal and assigning to just one specific model is very easy, the argument “use save when its specific to the model” seems moot. It’s just as easy to make a signal as the save.&lt;/p&gt;
&lt;p&gt;Where to put signals?&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;If it’s a signal related solely to one model, I recommend on the model&lt;/li&gt;
&lt;li&gt;If it’s a signal that is used on multiple places, I recommend a signals.py module (just make sure to add it to&lt;em&gt; __init__.py&lt;/em&gt; so that’s imported)&lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;Further reading&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://stackoverflow.com/questions/170337/django-signals-vs-overriding-save-method"&gt;&lt;a href="http://stackoverflow.com/questions/170337/django-signals-vs-overriding-save-method"&gt;http://stackoverflow.com/questions/170337/django-signals-vs-overriding-save-method&lt;/a&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.martin-geber.com/thought/2007/10/29/django-signals-vs-custom-save-method/"&gt;&lt;a href="http://www.martin-geber.com/thought/2007/10/29/django-signals-vs-custom-save-method/"&gt;http://www.martin-geber.com/thought/2007/10/29/django-signals-vs-custom-save-method/&lt;/a&gt;&lt;/a&gt; (old)&lt;/li&gt;
&lt;/ul&gt;</description><link>http://djangozen.com/post/14346752002</link><guid>http://djangozen.com/post/14346752002</guid><pubDate>Sat, 17 Dec 2011 02:53:47 -0500</pubDate></item><item><title>Content mirror and this site</title><description>&lt;p&gt;&lt;strong&gt;How this site is configured and some more details on content mirror.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I’ve been asked for this a couple of times, so here’s some details on how Content Mirror works on this site.&lt;/p&gt;
&lt;p&gt;This site’s main editing interface for editors (myself) is done in Plone. Plone is mirroring it’s content into a Postgres database, which is being synced to a Django site, you are then reading it in something served by Django.&lt;/p&gt;
&lt;h3&gt;Server configuration&lt;/h3&gt;
&lt;p&gt;My Plone site is running in a Virtual Machine on my Mac. It is in fact an out of the box Plone 3.x, that’s easy to install and set up. To that installation I added in &lt;a class="external-link" href="http://code.google.com/p/contentmirror/wiki/Installation"&gt;Content Mirror&lt;/a&gt; and &lt;a class="external-link" href="http://www.initd.org/svn/psycopg/"&gt;psycopg&lt;/a&gt;. For this I’m using &lt;a class="external-link" href="http://www.postgresql.org/"&gt;Postgres&lt;/a&gt;, it would work with any database, but I much prefer Postgres.&lt;/p&gt;
&lt;p&gt;Next I created a Postgres database locally. I did this locally because I wanted to develop the site and wanted to install and play with everything locally. Developing locally is fast and simple.&lt;/p&gt;
&lt;p&gt;So I’ve got Plone and Postgres installed locally with Content Mirror pushing content to Postgres. With that up and running I tried it out by adding in a few documents, publishing them and checking that everything worked.&lt;/p&gt;
&lt;p&gt;So here’s how the “About page” of Djangozen, you’ll notice it is vanilla out of the box Plone:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Plone view of About" class="image-inline" src="/images/31/"/&gt;&lt;/p&gt;
&lt;h3&gt;Building a front end&lt;/h3&gt;
&lt;p&gt;Once I’ve got everything going into the database, I can start to add in a front end. For this I chose Plango and then started modifying the heck out of it. &lt;a class="external-link" href="http://code.google.com/p/contentmirror/source/browse/#svn/frontends/plango"&gt;Plango is here&lt;/a&gt; and is a front end in Django. It has a simple URL resolver that simply grabs the request, then looks that up in the database. So &lt;em&gt;/about&lt;/em&gt; becomes a lookup in the database for a piece of content with no parent and an id of &lt;em&gt;about&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There’s certainly some opportunity for optimization in those URL look ups, but we’ll about that later. The nice thing about having that Django front end is that it’s a snap to add in comments, simple openid login and so on without doing any Plone development at all.&lt;/p&gt;
&lt;p&gt;The plugin’s section is added to and edited by end users, so that’s a Django app (that’s embarrasingly simple).&lt;/p&gt;
&lt;h3&gt;Deployment&lt;/h3&gt;
&lt;p&gt;Deployment of this site was actually very easy. I have a Webfaction account I use for various non-critical things. It’s cheap and easy to set up - I’m running 4 sites on it at the moment for under $10 a month.&lt;/p&gt;
&lt;p&gt;The Django code went into SVN. And then I made Django app on my server, copying down the code I’d developed locally. Then I added in Postgres database.&lt;/p&gt;
&lt;p&gt;To move data up is pretty simple, I stopped the local postgres and made an ssh tunnel. Restart Plone and it’s now writing to the remote postgres over the ssh tunnel. My script looks something like this:&lt;/p&gt;
&lt;pre&gt;sudo /etc/init.d/postgresql-8.3 stop
ssh -L 5432:server:5432 andymckay@server
sudo /etc/init.d/postgresql-8.3 start&lt;/pre&gt;
&lt;div&gt; &lt;/div&gt;
&lt;p&gt;The first time the connection is made, &lt;a class="external-link" href="http://code.google.com/p/contentmirror/source/browse/frontends/plango/update"&gt;just run the bulk deployment script&lt;/a&gt; and the content is uploaded. After that all content will be incrementally deployed.&lt;/p&gt;
&lt;h3&gt;Gotchas&lt;/h3&gt;
&lt;ul&gt;&lt;li&gt;There’s currently a bug in Content Mirror that means the ATEvent content type has none of the extra fields (such as startdate, enddate, location…). Only I seem to get this issue at the moment however.&lt;/li&gt;
&lt;li&gt;Changing the Postgres that the Plone site is talking to a lot can cause Plone to give errors, so try not to flip the Postgres database too often via the ssh tunnel.&lt;/li&gt;
&lt;li&gt;If you have a lot of content that is being added to the site on the front end, you loose a lot of the Plone advantage. For example I want people to be able to add events to Django zen and have a review step… there isn’t a backwards step, I can’t review content in Plone.&lt;/li&gt;
&lt;li&gt;Got to watch out for review states for things like navigation, RSS feeds, search and so on, if you want only published content to be viewed.&lt;/li&gt;
&lt;li&gt;Things will be written to the database without Django knowing about. So, for example, Plango has a full text search. A cron job runs every 5 minutes, looks for things that have been updated and adds or removes them from the full text search, as needed. A database trigger works well, until I found Webfaction doesn’t allow them.&lt;/li&gt;
&lt;li&gt;You need to fight Kupu to get it not to resolve uid’s in HTML so that if you embed an image in a document (such as this one) you can unresolve it.&lt;/li&gt;
&lt;li&gt;Not everything in Plone is going to be translated, but that’s part of the cost.&lt;/li&gt;
&lt;/ul&gt;&lt;h3&gt;Summary&lt;/h3&gt;
&lt;p&gt;For Djangozen it’s probably overkill. Although writing this blog post in Kupu, adding images etc has been quite a pleasure compared to the Django admin interface. But now most of the above gotchas have been resolved, it’s quite simple and quick to set this up and end up with a good site in no time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Update: &lt;/strong&gt;this doesn’t happen any more, it’s in tumblr now.&lt;/p&gt;</description><link>http://djangozen.com/post/14346726819</link><guid>http://djangozen.com/post/14346726819</guid><pubDate>Sat, 17 Dec 2011 02:52:35 -0500</pubDate></item><item><title>Keeping user profiles in sync</title><description>&lt;p&gt;&lt;strong&gt;Django provides a user profile as a way to extend a users information. This isn’t created automatically for you however when you create a new User, but it is pretty simple to do this.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The easiest way to do this is to use signals. By listening to the &lt;em&gt;post_save&lt;/em&gt; signal on users, you can create a user profile on a save.&lt;/p&gt;
&lt;p&gt;When the user object is deleted, the profile will be deleted, because the delete cascades. To use this, don’t forget to register in the class UserProfile into &lt;em&gt;AUTH_PROFILE_MODULE&lt;/em&gt; (see settings at the end):&lt;/p&gt;
&lt;pre&gt;from django.db import models
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist

class UserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)

def create_profile(sender, **kw):
    user = kw["instance"]
    if kw["created"]:
        up = UserProfile(user=user)
        up.save()

post_save.connect(create_profile, sender=User)&lt;/pre&gt;
&lt;p&gt;And here’s a test to demonstrate it working.&lt;/p&gt;
&lt;pre&gt;from django.test import TestCase
from models import UserProfile
from django.contrib.auth.models import User

class UserTest(TestCase):
    def testUser(self):
        u = User.objects.create(
             username='admin',
             email='andy@clearwind.ca')

        u.save()
        
        assert u.get_profile()
        assert User.objects.count() == 1
        assert UserProfile.objects.count() == 1
        
        u.delete()
        
        assert User.objects.count() == 0
        assert UserProfile.objects.count() == 0&lt;/pre&gt;
&lt;p&gt;Since this got asked on the django IRC channel I figured it had enough reason to justify a blog post.&lt;/p&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a href="http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/"&gt;&lt;a href="http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/"&gt;http://www.b-list.org/weblog/2006/jun/06/django-tips-extending-user-model/&lt;/a&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#auth-profile-module"&gt;&lt;a href="http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#auth-profile-module"&gt;http://docs.djangoproject.com/en/dev/ref/settings/?from=olddocs#auth-profile-module&lt;/a&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://docs.djangoproject.com/en/dev/topics/auth/#auth-profiles"&gt;&lt;a href="http://docs.djangoproject.com/en/dev/topics/auth/#auth-profiles"&gt;http://docs.djangoproject.com/en/dev/topics/auth/#auth-profiles&lt;/a&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description><link>http://djangozen.com/post/14346481212</link><guid>http://djangozen.com/post/14346481212</guid><pubDate>Sat, 17 Dec 2011 02:40:53 -0500</pubDate></item><item><title>Django at PyCon</title><description>&lt;p&gt;&lt;strong&gt;A wrap up of the happenings at PyCon.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Sadly I didn’t get to PyCon this year. In fact I haven’t ever been to PyCon, just what used to be the “Python Conference” which I think has been overtaken by PyCon.&lt;/p&gt;
&lt;p&gt;Looking at the chat and IRC logs makes me realise how many people I know there and wish I’d been able to go. Next year. After being around the Zope, then Plone, then Django communities, it’s amazing how many people I knew and how many people those communities touched. &lt;/p&gt;
&lt;p&gt;It also seemed this year that Django was a big component, perhaps due to the uptake in its popularity over the last year. Some links from what I’ve found:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a class="external-link" href="http://us.pycon.org/media/2009/talkdata/PyCon2009/045/state-of-django.pdf"&gt;Jacob’s State of Django&lt;/a&gt; talk (pdf)&lt;/li&gt;
&lt;li&gt;&lt;a class="external-link" href="http://us.pycon.org/media/2009/talkdata/PyCon2009/049/pinax-pyconPDF.pdf"&gt;James Tauber&lt;/a&gt; talks about Pinax (pdf)&lt;/li&gt;
&lt;li&gt;&lt;a class="external-link" href="http://us.pycon.org/media/2009/talkdata/PyCon2009/062/GAE_pycon_09_chicago.pdf"&gt;Manfred Schwendinger&lt;/a&gt; talks about Google App Engine (pdf)&lt;/li&gt;
&lt;li&gt;&lt;a class="external-link" href="http://us.pycon.org/media/2009/talkdata/PyCon2009/095/building-django-slides.pdf"&gt;Jacob&lt;/a&gt; talks about Django’s design decisions (pdf)&lt;/li&gt;
&lt;li&gt;&lt;a class="external-link" href="http://us.pycon.org/media/2009/talkdata/PyCon2009/085/winning.pdf"&gt;Carlos de la Guardi&lt;/a&gt;a talks about Content Mirror to serve Plone out through Django. Which is exactly what this site is doing. (pdf)&lt;/li&gt;
&lt;li&gt;&lt;a class="external-link" href="http://us.pycon.org/media/2009/talkdata/PyCon2009/054/PyCon_DoJ3.odp"&gt;Django on Jython&lt;/a&gt; by Jim Baker and Lee Soto (odp) &lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Some of the blog posts I found:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;&lt;a class="external-link" href="http://www.b-list.org/weblog/2009/mar/28/pycon-orm-panel/"&gt;James Bennett&lt;/a&gt; blogs on an ORM panel which included Django&lt;/li&gt;
&lt;li&gt;&lt;a class="external-link" href="http://lazypython.blogspot.com/2009/03/pycon-wrapup.html"&gt;Alex Gaynor’s&lt;/a&gt; PyCon wrap up&lt;/li&gt;
&lt;li&gt;&lt;a class="external-link" href="http://jacobian.org/speaking/2009/real-world-django/"&gt;Jacob&lt;/a&gt; gave a talk on “Real World Django” (which on the live monitoring point I would like to add in &lt;a class="external-link" href="http://www.areciboapp.com"&gt;Arecibo&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;For the sheer humour and gall of standing up in front of an audience and letting anyone on IRC type you have to &lt;a class="external-link" href="http://blip.tv/file/1932161"&gt;watch this talk&lt;/a&gt;. It’s not really about Django and is a bit off towards the end, but Ian Bicking is worth listening too. And the IRC chat is great.&lt;/p&gt;
&lt;p&gt;The most important thing though was of course:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;The &lt;a class="external-link" href="http://code.djangoproject.com/ticket/10668"&gt;Django pony going missing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a class="external-link" href="http://www.ponyransom.com/"&gt;pony being held for ransom&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a class="external-link" href="http://www.flickr.com/photos/bastispicks/3400633546/"&gt;pony slaying the Pinax team&lt;/a&gt; and escaping&lt;/li&gt;
&lt;li&gt;Phew!&lt;/li&gt;
&lt;/ul&gt;</description><link>http://djangozen.com/post/14346453065</link><guid>http://djangozen.com/post/14346453065</guid><pubDate>Sat, 17 Dec 2011 02:39:37 -0500</pubDate></item><item><title>Site launched</title><description>&lt;p&gt;&lt;strong&gt;Djangozen is now live in some sort of state, hopefully working.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There’s nothing more boring than that first “oh this site is live” post. Usually because the normal developer person has gone into marketing mode and really thinks the other people care about the site. I know you care. How could you not with new Django sites going live every day.&lt;/p&gt;
&lt;p&gt;Well here’s another. &lt;/p&gt;
&lt;p&gt;It covers things I want to know about Django above and beyond what’s on the main website. There’s lots of other sites out there that cover this stuff, but I wanted to start off with two things:&lt;/p&gt;
&lt;ul&gt;&lt;li&gt;Plugins. There’s a great site out there called &lt;a class="external-link" href="http://djangoplugables.com"&gt;djangoplugables&lt;/a&gt;, it has loads of products on it. However there’s a few features I wanted. You can’t add plugins or releases to it  (i think it only indexes google code), there’s no categorisation and no RSS feed. Once I’ve got tagging working, those features are all here.&lt;/li&gt;
&lt;li&gt;Clear Django. This is a book I’m starting to write that is a recipe style online book. It hasn’t got far as of the time of writing but it will all be online.&lt;/li&gt;
&lt;/ul&gt;&lt;p&gt;Of course all this is just empty words, with sites coming and going all the time, the real test is to come back in 6 months and see if I’m still here and doing this. Then you can really start to take notice.&lt;/p&gt;
&lt;p&gt;In the meantime please bear with me as I finish off the features, clean up the typos and clean up the user interface.&lt;/p&gt;</description><link>http://djangozen.com/post/14346409764</link><guid>http://djangozen.com/post/14346409764</guid><pubDate>Sat, 17 Dec 2011 02:37:34 -0500</pubDate></item></channel></rss>

