<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>elo80ka</title>
	<atom:link href="http://elo80ka.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://elo80ka.wordpress.com</link>
	<description>Life. Programming. Software.</description>
	<lastBuildDate>Mon, 19 Dec 2011 06:43:20 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='elo80ka.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>elo80ka</title>
		<link>http://elo80ka.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://elo80ka.wordpress.com/osd.xml" title="elo80ka" />
	<atom:link rel='hub' href='http://elo80ka.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Madness</title>
		<link>http://elo80ka.wordpress.com/2010/04/20/madness/</link>
		<comments>http://elo80ka.wordpress.com/2010/04/20/madness/#comments</comments>
		<pubDate>Tue, 20 Apr 2010 00:20:09 +0000</pubDate>
		<dc:creator>elo80ka</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Firefox 3.5]]></category>
		<category><![CDATA[Madness]]></category>

		<guid isPermaLink="false">http://elo80ka.wordpress.com/?p=46</guid>
		<description><![CDATA[Tagged: Firefox 3.5, Madness<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=46&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div id="attachment_47" class="wp-caption alignleft" style="width: 310px"><a rel="attachment wp-att-47" href="http://elo80ka.wordpress.com/2010/04/20/madness/madness/"><img class="size-medium wp-image-47 " style="border:0 none;" title="Madness" src="http://elo80ka.files.wordpress.com/2010/04/madness.png?w=300&#038;h=227" alt="" width="300" height="227" /></a><p class="wp-caption-text">Firefox, with less than 2 dozen tabs open, running on my AMD Turion laptop with 2GB of RAM.</p></div>
<p><a rel="attachment wp-att-47" href="http://elo80ka.wordpress.com/2010/04/20/madness/madness/"></a></p>
<br /> Tagged: <a href='http://elo80ka.wordpress.com/tag/firefox-3-5/'>Firefox 3.5</a>, <a href='http://elo80ka.wordpress.com/tag/madness/'>Madness</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/elo80ka.wordpress.com/46/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/elo80ka.wordpress.com/46/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/elo80ka.wordpress.com/46/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/elo80ka.wordpress.com/46/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/elo80ka.wordpress.com/46/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/elo80ka.wordpress.com/46/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/elo80ka.wordpress.com/46/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/elo80ka.wordpress.com/46/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/elo80ka.wordpress.com/46/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/elo80ka.wordpress.com/46/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/elo80ka.wordpress.com/46/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/elo80ka.wordpress.com/46/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/elo80ka.wordpress.com/46/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/elo80ka.wordpress.com/46/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=46&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://elo80ka.wordpress.com/2010/04/20/madness/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f1f096a625c53ca22ee8b57b19724e56?s=96&#38;d=&#38;r=PG" medium="image">
			<media:title type="html">elo80ka</media:title>
		</media:content>

		<media:content url="http://elo80ka.files.wordpress.com/2010/04/madness.png?w=300" medium="image">
			<media:title type="html">Madness</media:title>
		</media:content>
	</item>
		<item>
		<title>Django Dynamic Formset, v1.2</title>
		<link>http://elo80ka.wordpress.com/2010/04/13/django-dynamic-formset-v1-2/</link>
		<comments>http://elo80ka.wordpress.com/2010/04/13/django-dynamic-formset-v1-2/#comments</comments>
		<pubDate>Tue, 13 Apr 2010 10:23:14 +0000</pubDate>
		<dc:creator>elo80ka</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://elo80ka.wordpress.com/?p=43</guid>
		<description><![CDATA[So, it&#8217;s two months later than I&#8217;d estimated, but sometime this morning, I committed version 1.2. In spite of the delay (which is a story for another time), I&#8217;m pretty excited about this release &#8212; I got to add a couple of nifty features, and squash some bugs in the process (thanks for the bug [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=43&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>So, it&#8217;s two months later than I&#8217;d estimated, but sometime this morning, I committed version 1.2. In spite of the delay (which is a story for another time), I&#8217;m pretty excited about this release &#8212; I got to add a couple of nifty features, and squash some bugs in the process (thanks for the bug reports and patches, guys).</p>
<p>Here&#8217;s the list of changes:</p>
<ul>
<li><span style="font-size:13.3333px;">Inline formsets created with &#8220;can_delete&#8221; set to True are now supported properly;  clicking the &#8220;remove&#8221; link hides the form and sets the DELETE field, so Django  handles the deleting when the page is POSTed.</span></li>
<li><span style="font-size:13.3333px;">Added form templates: you can now specify a form that will be cloned to generate the forms in the formset. As a side-effect, you can now delete all forms in a formset, and the &#8220;add&#8221; link still works as expected.</span></li>
<li><span style="font-size:13.3333px;">Clicking the &#8220;add&#8221; link now clones the last form, instead of the first; this works much better in the admin, especially if you have one or more extra forms (thanks <a href="http://justinhamade.blogspot.com/">justhamade</a>).</span></li>
<li><span style="font-size:13.3333px;">Added an optional setting &#8220;extraClasses&#8221;; set this is an array of CSS classes, and they&#8217;ll be applied to the formset&#8217;s rows in turn. So, to get the row-striping effect in the Django admin, you&#8217;d do something like this: <pre class="brush: jscript;">
$('...').formset({extraClasses: ['row1', 'row2']});
</pre>
<p>Adding and removing forms keeps the classes in sync, so your stripes don&#8217;t get all mix&#8217;d up &#8212; hopefully, this is a feature, but time will tell.</p>
<p></span></li>
<li><span style="font-size:13.3333px;">Updated examples and documentation.</span></li>
</ul>
<p>As always, you can download the latest release from the <a href="http://code.google.com/p/django-dynamic-formset/">Google Code</a> page, or use the links below:</p>
<ul>
<li><a href="http://django-dynamic-formset.googlecode.com/files/jquery.formset-1.2.zip">Source code, minified (using jsmin) version and docs</a></li>
<li><a href="http://django-dynamic-formset.googlecode.com/files/jquery.formset-1.2-with-examples.zip">Source code, minified version, docs and demo Django project</a></li>
</ul>
<br /> Tagged: <a href='http://elo80ka.wordpress.com/tag/django/'>Django</a>, <a href='http://elo80ka.wordpress.com/tag/jquery/'>jQuery</a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/elo80ka.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/elo80ka.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/elo80ka.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/elo80ka.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/elo80ka.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/elo80ka.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/elo80ka.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/elo80ka.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/elo80ka.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/elo80ka.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/elo80ka.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/elo80ka.wordpress.com/43/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/elo80ka.wordpress.com/43/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/elo80ka.wordpress.com/43/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=43&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://elo80ka.wordpress.com/2010/04/13/django-dynamic-formset-v1-2/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f1f096a625c53ca22ee8b57b19724e56?s=96&#38;d=&#38;r=PG" medium="image">
			<media:title type="html">elo80ka</media:title>
		</media:content>
	</item>
		<item>
		<title>Django Dynamic Formset v1.1 released</title>
		<link>http://elo80ka.wordpress.com/2009/11/30/django-dynamic-formset-v1-1-released/</link>
		<comments>http://elo80ka.wordpress.com/2009/11/30/django-dynamic-formset-v1-1-released/#comments</comments>
		<pubDate>Mon, 30 Nov 2009 17:17:37 +0000</pubDate>
		<dc:creator>elo80ka</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://elo80ka.wordpress.com/?p=33</guid>
		<description><![CDATA[Almost two months ago, I released the Django Dynamic Formset plugin, with the hope that someone out there might find it useful. Since then, I&#8217;ve received a good bit of feedback, which I&#8217;ve been meaning to roll into a new release. Last weekend, I finally made some time to update the documentation and examples, and [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=33&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Almost two months ago, I released the <a href="http://code.google.com/p/django-dynamic-formset/">Django Dynamic Formset</a> plugin, with the hope that someone out there might find it useful. Since then, I&#8217;ve received a good bit of feedback, which I&#8217;ve been meaning to roll into a new release. Last weekend, I finally made some time to update the documentation and examples, and today, I updated the project site on Google Code.</p>
<p>This new release contains two bugfixes (thanks to Wilson.Andrew.J and an anonymous fella), as well as a few more examples (thanks <a href="http://escolareadevelopment.blogspot.com/">lfborjas</a>). Here&#8217;s the short list of changes:</p>
<ul>
<li>Fixed bug that erased the values on all checkboxes/radiobuttons in a cloned form</li>
<li>Fixed a bug in the way the &#8220;add new&#8221; event handler was being assigned (discoverd this while adding support for multiple formsets)</li>
<li>Added support for multiple formsets on the same page &#8212; see documentation</li>
<li>Added two new examples</li>
<li>Updated the documentation</li>
</ul>
<p>You can download the releases from the <a href="http://code.google.com/p/django-dynamic-formset/">Google Code page</a>, or use the links below:</p>
<ul>
<li><a href="http://django-dynamic-formset.googlecode.com/files/jquery.formset-1.1.zip">Source code, minified (using jsmin) version and docs</a></li>
<li><a href="http://django-dynamic-formset.googlecode.com/files/jquery.formset-1.1-with-examples.zip">Source code, minified version, docs and demo Django project</a></li>
</ul>
<p>Big Thanks to all those who reported bugs, contributed patches or just left comments &#8212; you guys rock.</p>
<br /> Tagged: Django, jQuery <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/elo80ka.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/elo80ka.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/elo80ka.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/elo80ka.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/elo80ka.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/elo80ka.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/elo80ka.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/elo80ka.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/elo80ka.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/elo80ka.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/elo80ka.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/elo80ka.wordpress.com/33/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/elo80ka.wordpress.com/33/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/elo80ka.wordpress.com/33/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=33&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://elo80ka.wordpress.com/2009/11/30/django-dynamic-formset-v1-1-released/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f1f096a625c53ca22ee8b57b19724e56?s=96&#38;d=&#38;r=PG" medium="image">
			<media:title type="html">elo80ka</media:title>
		</media:content>
	</item>
		<item>
		<title>Using a FormWizard in the Django admin</title>
		<link>http://elo80ka.wordpress.com/2009/10/28/using-a-formwizard-in-the-django-admin/</link>
		<comments>http://elo80ka.wordpress.com/2009/10/28/using-a-formwizard-in-the-django-admin/#comments</comments>
		<pubDate>Wed, 28 Oct 2009 01:59:50 +0000</pubDate>
		<dc:creator>elo80ka</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Tutorial]]></category>

		<guid isPermaLink="false">http://elo80ka.wordpress.com/?p=23</guid>
		<description><![CDATA[A few weeks ago, I saw this question on Stackoverflow, asking how to integrate a Form Wizard with the Django admin. Although there&#8217;s an accepted answer, it doesn&#8217;t include any code, and doesn&#8217;t appear to take advantage of Django 1.1 features (more on these later), which make integrating custom views with the admin much easier [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=23&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A few weeks ago, I saw <a href="http://stackoverflow.com/questions/1096607/incorporate-custom-template-into-the-django-admin-interface-and-session">this question</a> on Stackoverflow, asking how to integrate a Form Wizard with the Django admin. Although there&#8217;s an accepted answer, it doesn&#8217;t include any code, and doesn&#8217;t appear to take advantage of Django 1.1 features (more on these later), which make integrating custom views with the admin much easier and more seamless. I thought I&#8217;d share my solution here, in case there&#8217;s others out there asking the same question. You can <a href="#download_demo_project">download the source code</a> for this example, if you&#8217;d like to follow along.</p>
<p>For our example, we&#8217;ll develop a wizard to add employers to a database, for a fictional recruitment application. Adding an employer will be a three-step process:</p>
<ol>
<li>First, choose a username and password, which the employer will use to login. Make sure to verify the password, by entering it twice.</li>
<li>Enter the name and email address of the contact person for this employer.</li>
<li>Enter the company&#8217;s name, description, address and website URL.</li>
</ol>
<p>Clicking on &#8220;add new&#8221; on the employer changelist page, should display the wizard, rather than the default form .</p>
<h3>Assumptions:</h3>
<p>A number of features I mention are specific to Django 1.1 &#8212; if you&#8217;re already using 1.1, great! If not, maybe this&#8217;ll give you one more reason to upgrade? I sure hope so. I&#8217;ll assume you already have a functional installation of Django; head over to <a href="http://docs.djangoproject.com/en/dev/topics/install/">the docs</a> if you need help setting up Django. I&#8217;ll also assume you know how to start a Django project &#8212; there&#8217;s plenty of introductory tutorials out there, including <a href="http://docs.djangoproject.com/en/dev/intro/tutorial01/">this one</a> in the Django docs.</p>
<p>All set? Well, let&#8217;s get started then.</p>
<h3>Step 1: Setup</h3>
<ol>
<li>Create a new Django project and add a new app to it (We&#8217;ll call it &#8220;testapp&#8221;). Add the app to INSTALLED_APPS in your settings.py. Also, add &#8220;django.contrib.admin&#8221; to INSTALLED_APPS.</li>
<li>Configure the DATABASE_* settings for your database of choice &#8212; I&#8217;ll be using SQLite.</li>
<li>Add the path(s) to the folder where you&#8217;ll store your templates in TEMPLATE_DIRS</li>
<li>Edit the main Urlconf, and follow the comments in it to enable the admin urls.</li>
<li>Run &#8220;syncdb&#8221; to create the database tables, then &#8220;runserver&#8221; to start the development server.</li>
</ol>
<p>Done? On to step 2 then.</p>
<h3>Step 2: Create the model</h3>
<p>Next, we&#8217;ll create the Employer model. Save the code below as &#8220;testapp/models.py&#8221; (move your mouse over the code below, and click the &#8220;copy to clipboard&#8221; link, then paste into a new file):</p>
<p><pre class="brush: python;">
from django.db import models
from django.contrib.auth.models import User

class Employer(models.Model):
    user = models.OneToOneField(User)
    company_name = models.CharField(max_length=60)
    company_description = models.TextField(blank=True)
    address = models.TextField()
    website = models.URLField(verify_exists=False, blank=True)

    class Meta:
        ordering = ('company_name',)

    def __unicode__(self):
        return self.company_name
</pre></p>
<p>Pretty simple stuff. We&#8217;ll store the login and contact information for an employer in the User table, and the company information in the Employer table. Next, we&#8217;ll create our forms.</p>
<h3>Step 3: Create the forms</h3>
<p>We&#8217;ll need three forms for our wizard, one for each step of the employer creation process. Here&#8217;s the code (save as &#8220;testapp/forms.py&#8221;):</p>
<p><pre class="brush: python;">
from django import forms
from django.forms import fields, models, widgets
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django.contrib.formtools.wizard import FormWizard
from django.utils.encoding import force_unicode
from testapp.models import Employer

class ContactForm(forms.Form):
    first_name = fields.CharField(max_length=50, label=&quot;Contact's first name&quot;)
    last_name = fields.CharField(max_length=50, label=&quot;Contact's last name&quot;)
    email = fields.EmailField(label=&quot;Contact's email address&quot;)

class EmployerForm(models.ModelForm):
    class Meta:
        model = Employer
        exclude = ('user',)
</pre></p>
<p>For the first step in the wizard, we&#8217;ll reuse the UserCreationForm from <em>django.contrib.auth.forms</em>. The ContactForm and EmployerForm handle the second and third steps, respectively. So far, this is all pretty basic forms stuff; if any of this is new to you, you really should check out the <a href="http://docs.djangoproject.com/en/dev/topics/forms/">forms documentation</a>.</p>
<p>Next, we&#8217;ll create our wizard. A wizard is simply a subclass of <em>django.contrib.formtools.wizard.FormWizard</em>, which defines a &#8220;done&#8221; method, specifying what action to perform once all the wizard&#8217;s forms have been submitted; the actual forms are passed as a list to the subclass&#8217;s constructor. Once you&#8217;ve created an instance of your wizard, you can use it in a Urlconf, just like any other view (remember, a view doesn&#8217;t have to be a function &#8212; it just has to be <em><a href="http://stackoverflow.com/questions/111234/what-is-a-callable-in-python">callable</a></em>).</p>
<p>We&#8217;ll create the wizard below the other forms:</p>
<p><pre class="brush: python;">
class EmployerCreationWizard(FormWizard):
    @property
    def __name__(self):
        return self.__class__.__name__

    def done(self, request, form_list):
        data = {}
        for form in form_list:
            data.update(form.cleaned_data)
        # First, create user:
        user = User(
            username=data['username'],
            first_name=data['first_name'],
            last_name=data['last_name'],
            email=data['email']
        )
        user.set_password(data['password1'])
        user.save()
        # Next, create employer:
        employer = Employer.objects.create(
            user=user,
            company_name=data['company_name'],
            address=data['address'],
            company_description=data.get('company_description', ''),
            website=data.get('website', '')
        )
        # TODO: Display success message and redirect to changelist.

create_employer = EmployerCreationWizard([UserCreationForm, ContactForm, EmployerForm])
</pre></p>
<p>The code above should be mostly straightforward &#8212; we create an instance of User, save it, then pass it to the &#8220;create&#8221; method of the Employer model (well, strictly speaking, it&#8217;s the Employer model&#8217;s manager). Notice we call &#8220;set_password&#8221; on the User instance to handle the password hashing stuff for us.</p>
<p>We also define a &#8220;__name__&#8221; property on the wizard. We do this because I&#8217;ve noticed a number of Django decorators raise an AttributeError when you use them to decorate an instance, complaining they can&#8217;t find __name__ (Python instances don&#8217;t have a __name__ property, though functions and classes do). Since we&#8217;ll be decorating our wizard instance in a moment, we provide the __name__ property, so everyone&#8217;s happy.</p>
<p>See the #TODO at the end? We&#8217;ll be adding code to handle that in a moment. First, though, a small detour to register our Employer model with the admin.</p>
<h3>Step 4: Register the Employer model with the admin</h3>
<p>Now things start to get interesting. We&#8217;ll take advantage of two Django 1.1 features, to integrate the create_employer wizard with the admin:</p>
<ol>
<li>The &#8220;ModelAdmin.<a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_urls">get_urls</a>&#8221; method returns the URLs to be used for a ModelAdmin subclass in the same way as a Urlconf; because of this, you can easily add new urlpatterns to your ModelAdmin subclass.</li>
<li>The &#8220;ModelAdmin.admin_site.admin_view&#8221; wrapper can be applied to any view, to mark it as an admin view. Each time the view is accessed, it checks the current user&#8217;s permissions and redirects to the login page, if necessary. It also marks the wrapped view as non-cacheable, by default (in effect, <em>admin_view</em> is equivalent to applying the <em>staff_member_required</em> and <em>never_cache</em> decorators).</li>
</ol>
<p>Here&#8217;s the code for our ModelAdmin subclass; save this as &#8220;testapp/admin.py&#8221;:</p>
<p><pre class="brush: python;">
from django.conf.urls.defaults import url, patterns
from django.contrib import admin
from django.utils.encoding import force_unicode
from django.utils.functional import update_wrapper
from testapp.models import Employer
from testapp.forms import create_employer

class EmployerAdmin(admin.ModelAdmin):
    def get_urls(self):
        def wrap(view):
            def wrapper(*args, **kwds):
                kwds['admin'] = self   # Use a closure to pass this admin instance to our wizard
                return self.admin_site.admin_view(view)(*args, **kwds)
            return update_wrapper(wrapper, view)

        urlpatterns = patterns('',
            url(r'^add/$',
                wrap(create_employer),
                name='testapp_employer_add')
        )
        urlpatterns += super(EmployerAdmin, self).get_urls()
        return urlpatterns

admin.site.register(Employer, EmployerAdmin)
</pre></p>
<p>There&#8217;s a few things to note in the above code:</p>
<ol>
<li>We bind the <em>create_employer</em> wizard to the pattern &#8216;^add/$&#8217;, which is the same pattern used by <em>ModelAdmin.add_view</em>; since our urlpattern appears before the default patterns, we&#8217;ve effectively overriden the default add view.</li>
<li>We define a decorator &#8220;wrap&#8221;, which applies the admin_site.admin_view wrapper to our wizard, and calls &#8220;update_wrapper&#8221; on the wrapped function to preserve its name and docstring.</li>
<li>We pass a reference to the current ModelAdmin instance to the wizard; this allows us access to the admin from within the wizard&#8217;s methods.</li>
</ol>
<p>If you browse to the admin add view for the employer (if you&#8217;re using the development server defaults, your URl should look like: <a href="http://localhost:8000/admin/testapp/employer/add/">http://localhost:8000/admin/testapp/employer/add/</a>), you should get a TemplateNotFound error. Let&#8217;s create a template, so we can see how everything looks.</p>
<h3>Step 5: Create a template</h3>
<p>By default, the wizard looks for the template &#8220;forms/wizard.html&#8221;. You can change this by overriding the &#8220;get_template&#8221; method, but we&#8217;ll use the default for now. Save the HTML below as &#8220;templates/forms/wizard.html&#8221; (assuming your TEMPLATE_DIRS in settings.py includes &#8220;templates&#8221;):</p>
<p><pre class="brush: xml;">
{% extends &quot;admin/change_form.html&quot; %}
{% load i18n %}

{% block content %}
&lt;div id=&quot;content-main&quot;&gt;
    &lt;form {% if form.form.is_multipart %}enctype=&quot;multipart/form-data&quot; {% endif %}method=&quot;post&quot; action=&quot;&quot; id=&quot;{{ opts.module_name }}_form&quot;&gt;
        &lt;div&gt;
            {% if form.form.errors %}
            &lt;p class=&quot;errornote&quot;&gt;
                {% blocktrans count form.form.errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %}
            &lt;/p&gt;
            &lt;ul class=&quot;errorlist&quot;&gt;
                {% for error in form.form.non_field_errors %}
                &lt;li&gt;{{ error }}&lt;/li&gt;{% endfor %}
            &lt;/ul&gt;
            {% endif %}

            {% for fieldset in form %}
              {% include &quot;admin/includes/fieldset.html&quot; %}
            {% endfor %}

            &lt;input type=&quot;hidden&quot; name=&quot;{{ step_field }}&quot; value=&quot;{{ step0 }}&quot; /&gt;
            {{ previous_fields|safe }}

            &lt;div class=&quot;submit-row&quot;&gt;
                &lt;input type=&quot;submit&quot; value=&quot;{% ifequal step step_count %}Finish{% else %}Next &amp;raquo;{% endifequal %}&quot; class=&quot;default&quot; name=&quot;_save&quot; /&gt;
            &lt;/div&gt;

            &lt;script type=&quot;text/javascript&quot;&gt;document.getElementById(&quot;{{ form.first_field.auto_id }}&quot;).focus();&lt;/script&gt;
        &lt;/div&gt;
    &lt;/form&gt;
&lt;/div&gt;
{% endblock %}
</pre></p>
<p>Now go back to the admin add view for employer and hit refresh.</p>
<p>Oops.</p>
<p>What happened to the breadcrumbs? The page title? The form??</p>
<p>Don&#8217;t despair though&#8230;the hard part&#8217;s over. Go on and take a break &#8212; stretch, get coffee, grab a snack, talk to another human being.</p>
<p>Back already? You&#8217;re pretty quick. Let&#8217;s fix the template now, shall we?</p>
<h3>Step 6: Putting things in Context</h3>
<p>As you&#8217;ve probably figured out by now, our template context is a few variables short. From the <em>ModelAdmin</em> source code (somewhere around line 772 in &#8220;django/contrib/admin/options.py&#8221;):</p>
<p><pre class="brush: python;">
context = {
            'title': _('Add %s') % force_unicode(opts.verbose_name),
            'adminform': adminForm,
            'is_popup': request.REQUEST.has_key('_popup'),
            'show_delete': False,
            'media': mark_safe(media),
            'inline_admin_formsets': inline_admin_formsets,
            'errors': helpers.AdminErrorList(form, formsets),
            'root_path': self.admin_site.root_path,
            'app_label': opts.app_label,
        }
</pre></p>
<p>We can safely ignore a number of these (such as &#8220;is_popup&#8221;, &#8220;show_delete&#8221; and &#8220;inline_admin_formsets&#8221;), but the others need to be present for the template to render correctly. Fortunately, the <em>FormWizard </em>provides a solution: the &#8220;parse_params&#8221; method.</p>
<p>According to the docstring, <em>parse_params</em> is a &#8220;hook for setting some state, given the request object, and whatever *args and **kwargs were passed to <em>__call__()</em>&#8220;. Remember the &#8220;admin&#8221; keyword argument we passed in <em>get_urls</em>? That gets passed along to <em>parse_params</em>, where we can extract it, and use it to populate <em>FormWizard.extra_context</em>. Add the code below to the <em>EmployerCreationWizard</em> in &#8220;testapp/forms.py&#8221;:</p>
<p><pre class="brush: python;">
def parse_params(self, request, admin=None, *args, **kwargs):
    self._model_admin = admin # Save this so we can use it later.
    opts = admin.model._meta # Yes, I know we could've done Employer._meta, but this is cooler :)
    self.extra_context.update({
        'title': u'Add %s' % force_unicode(opts.verbose_name),
        'current_app': admin.admin_site.name,
        'has_change_permission': admin.has_change_permission(request),
        'add': True,
        'opts': opts,
        'root_path': admin.admin_site.root_path,
        'app_label': opts.app_label,
    })
</pre></p>
<p>Go to the employer add view again and hit refresh&#8230;much better. Our title now shows up, and breadcrumbs work. But what is up with our form?</p>
<p>It turns out that the &#8220;form&#8221; our template expects isn&#8217;t an instance of &#8220;django.forms.BaseForm&#8221;, but rather an instance of &#8220;django.contrib.admin.helpers.AdminForm&#8221;. What we need is to convert our <em>BaseForm </em>instance to an <em>AdminForm</em> instance. Again, the <em>FormWizard</em> comes to the rescue, by providing the &#8220;render_template&#8221; method. Add the code below to the <em>EmployerCreationWizard</em>, below <em>parse_params</em>:</p>
<p><pre class="brush: python;">
def render_template(self, request, form, previous_fields, step, context=None):
    from django.contrib.admin.helpers import AdminForm
    # Wrap this form in an AdminForm so we get the fieldset stuff:
    form = AdminForm(form, [(
        'Step %d of %d' % (step + 1, self.num_steps()),
        {'fields': form.base_fields.keys()}
        )], {})
    context = context or {}
    context.update({
        'media': self._model_admin.media + form.media
    })
    return super(EmployerCreationWizard, self).render_template(request, form, previous_fields, step, context)
</pre></p>
<p>The <em>AdminForm </em>constructor takes a form instance, a list of <a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.fieldsets">fieldsets</a> and a dictionary of <a href="http://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.prepopulated_fields">prepopulated fields</a>. We pass it the form instance passed to <em>render_template</em>, a single fieldset comprising all the fields in the form, and an empty dictionary (since we don&#8217;t care about the prepopulated fields). Next, we update the supplied context with the form media, then pass both the form and the updated context to the superclass <em>render_template</em>.</p>
<p>Go to the add view once more, and hit refresh. Sweet, eh?</p>
<h3>Step 7: Wrapping up</h3>
<p>Remember that #TODO in <em>EmployerCreationWizard.done</em>? Let&#8217;s fix that now. Replace the #TODO line with the following lines:</p>
<p><pre class="brush: python;">
# Display success message and redirect to changelist:
return self._model_admin.response_add(request, employer)
</pre></p>
<p>That&#8217;s it, we&#8217;re done. Go on over to the add view and try adding a couple of employers.</p>
<p>I hope someone out there finds this useful. If you&#8217;ve got other tips for integrating custom views with the admin, <a href="#respond">share them in the comments</a> (or, post a link to an article you wrote on your blog).</p>
<h4 id="download_demo_project">Download the demo project:</h4>
<p><a href="http://stan.madueke.googlepages.com/customadmin.zip">customadmin.zip (~7.49KB)</a></p>
<br /> Tagged: Django, Programming, Tutorial <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/elo80ka.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/elo80ka.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/elo80ka.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/elo80ka.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/elo80ka.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/elo80ka.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/elo80ka.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/elo80ka.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/elo80ka.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/elo80ka.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/elo80ka.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/elo80ka.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/elo80ka.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/elo80ka.wordpress.com/23/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=23&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://elo80ka.wordpress.com/2009/10/28/using-a-formwizard-in-the-django-admin/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f1f096a625c53ca22ee8b57b19724e56?s=96&#38;d=&#38;r=PG" medium="image">
			<media:title type="html">elo80ka</media:title>
		</media:content>
	</item>
		<item>
		<title>jQuery plugin: chained select lists</title>
		<link>http://elo80ka.wordpress.com/2009/10/14/jquery-plugin-chained-select-lists/</link>
		<comments>http://elo80ka.wordpress.com/2009/10/14/jquery-plugin-chained-select-lists/#comments</comments>
		<pubDate>Wed, 14 Oct 2009 12:48:20 +0000</pubDate>
		<dc:creator>elo80ka</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://elo80ka.wordpress.com/?p=16</guid>
		<description><![CDATA[A few days ago I was looking for a jQuery plugin that would allow me link select lists together, so that selecting an option in one list (the parent) would update the options in the other list (the target). I&#8217;d used linkedSelect on a previous project, but for some reason, my ISP kept returning &#8220;IP [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=16&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>A few days ago I was looking for a jQuery plugin that would allow me link select lists together, so that selecting an option in one list (the parent) would update the options in the other list (the target). I&#8217;d used <a href="http://www.msxhost.com/jquery/linked-selects/linkedSelect.zip">linkedSelect</a> on a previous project, but for some reason, my ISP kept returning &#8220;IP has been banned&#8221; each time I tried to browse to the site.</p>
<p>As it turns out, this was a good thing. Eventually, I found <a href="http://remysharp.com/2007/09/18/auto-populate-multiple-select-boxes/">this post</a> on Remy Sharp&#8217;s blog, and his selectChain plugin was almost exactly what I was looking for. Almost.<br />
There were a few changes I needed to make first:</p>
<ol>
<li>Add support for the <a href="http://docs.jquery.com/Plugins/Metadata/metadata">metadata plugin</a>: since I&#8217;ll mostly be using this in my Django projects, being able to specify plugin options declaratively means I can wrap the plugin in a custom widget.</li>
<li>Add support for caching</li>
<li>Update target list when the page is loaded, if the parent list has an option selected.</li>
<li>Preserve the selected option in the target list, if possible (as long as the updated options contain the previous option), when it is updated</li>
<li>Add a few niceties, such as a preloader GIF :)</li>
</ol>
<p>To use the plugin, <a href="http://stan.madueke.googlepages.com/jquery.chainedSelect.min.js">download it</a> and include a reference to it in your HTML page (don&#8217;t forget to include a reference to jQuery first!). I&#8217;ll assume, you&#8217;ve already written the server-side code in your <a href="http://www.djangoproject.com/">choice framework</a>. If you&#8217;d like to be able to customize the plugin behavior declaratively, for specific selects, you&#8217;ll also need to download the <a href="http://docs.jquery.com/Plugins/Metadata/metadata">metadata plugin</a>.</p>
<h3>Examples</h3>
<p>We&#8217;ll use the following HTML:</p>
<p><pre class="brush: xml;">
&lt;form method=&quot;post&quot; action=&quot;...&quot;&gt;
  &lt;label for=&quot;id_author&quot;&gt;Author:&lt;/label&gt;
  &lt;select name=&quot;author&quot; id=&quot;id_author&quot;&gt;
    &lt;option value=&quot;1&quot;&gt;Enid Blyton&lt;/option&gt;
    &lt;option value=&quot;2&quot;&gt;J. K. Rowling&lt;/option&gt;
    &lt;option value=&quot;3&quot;&gt;Roald Dahl&lt;/option&gt;
  &lt;/select&gt;
  &lt;label for=&quot;id_book&quot;&gt;Book:&lt;/label&gt;
  &lt;select name=&quot;book&quot; id=&quot;id_book&quot;&gt;
  &lt;/select&gt;
&lt;/form&gt;
</pre></p>
<p>Include the following script before the closing BODY tag, or in your HEAD:</p>
<p><pre class="brush: jscript;">
$(function() {
  $('#id_book').chainedSelect({
    parent: '#id_author',
    url: 'http://your.server/app',
    value: 'id',
    label: 'text'
  });
});
</pre></p>
<p>That&#8217;s it. Your server application should return a JSON-encoded list of objects, having &#8220;id&#8221; and &#8220;text&#8221; properties. The &#8220;id&#8221; will be used as the value of the generated option, the &#8220;text&#8221; as its label. Selecting an author from the list, should display a list of their books.</p>
<p>If you&#8217;re using the metadata plugin, you can move the options into the target select list. Change the HTML for the &#8220;book&#8221; list to this:</p>
<p><pre class="brush: xml;">
&lt;select name=&quot;book&quot; id=&quot;id_book&quot; class=&quot;chainedSelect {parent: '#id_author', url: 'http://your.server/app', value: 'id', label: 'text'}&quot;&gt;
&lt;/select&gt;
</pre></p>
<p>Then, replace the previous script with the following:</p>
<p><pre class="brush: jscript;">
$(function() {
  $('.chainedSelect').chainedSelect();
});
</pre></p>
<p>Simpler, isn&#8217;t it?</p>
<h3>Options</h3>
<p>Here&#8217;s a list of options you can pass, either as metadata, or in the call to &#8220;$.chainedSelect&#8221;, to customize the plugin:</p>
<ul>
<li><em>parent:</em> A jQuery ID selector, for the parent list &#8211; must begin with a &#8216;#&#8217;. Required.</li>
<li><em>url:</em> The URL to the server component. The server will be passed a single querystring parameter named &#8220;q&#8221;, whose value will be the selected option in the parent list. It should return a JSON-encoded list of objects, which will be used to populate the target list. Required.</li>
<li><em>value:</em> The property in the objects returned from the server, which should be used as the value for the generated option. Defaults to &#8220;pk&#8221;</li>
<li><em>label:</em> The property in the objects returned from the server, which should be used as the label for the generated option. Defaults to &#8220;name&#8221;</li>
<li><em>type:</em> The HTTP method used to submit the data to the server &#8211; defaults to &#8220;GET&#8221;.</li>
<li><em>preloadUrl:</em> A URL to a GIF image, displayed while waiting for an AJAX request to complete. For best results, images should be as small as possible &#8211; no larger than 16&#215;16 pixels</li>
<li><em>error:</em> Use this to specify a function that will be called if the AJAX request returns an error</li>
</ul>
<h3>Prerequisites</h3>
<p><a href="http://jquery.com/">jQuery</a>, of course (tested with 1.2.6)<br />
A server-side component, to generate the <a href="http://www.json.org/">JSON</a> used to populate the select lists</p>
<h3>Download</h3>
<p><a href="http://stan.madueke.googlepages.com/jquery.chainedSelect.js">jquery.chainedSelect source (6.3KB)</a><br />
<a href="http://stan.madueke.googlepages.com/jquery.chainedSelect.min.js">jquery.chainedSelect minified (2.1KB)</a></p>
<p>If you find this useful, or have any questions, ideas or issues, <a href="#respond">leave a comment</a>.</p>
<br /> Tagged: jQuery <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/elo80ka.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/elo80ka.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/elo80ka.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/elo80ka.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/elo80ka.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/elo80ka.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/elo80ka.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/elo80ka.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/elo80ka.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/elo80ka.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/elo80ka.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/elo80ka.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/elo80ka.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/elo80ka.wordpress.com/16/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=16&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://elo80ka.wordpress.com/2009/10/14/jquery-plugin-chained-select-lists/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f1f096a625c53ca22ee8b57b19724e56?s=96&#38;d=&#38;r=PG" medium="image">
			<media:title type="html">elo80ka</media:title>
		</media:content>
	</item>
		<item>
		<title>jQuery plugin: Django Dynamic Formset</title>
		<link>http://elo80ka.wordpress.com/2009/10/10/jquery-plugin-django-dynamic-formset/</link>
		<comments>http://elo80ka.wordpress.com/2009/10/10/jquery-plugin-django-dynamic-formset/#comments</comments>
		<pubDate>Sat, 10 Oct 2009 21:27:06 +0000</pubDate>
		<dc:creator>elo80ka</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Django]]></category>
		<category><![CDATA[jQuery]]></category>

		<guid isPermaLink="false">http://elo80ka.wordpress.com/?p=8</guid>
		<description><![CDATA[Several months ago, I posted this snippet over at Django Snippets. Since then, I&#8217;ve used it a few times, and eventually made it into a jQuery plugin. I always intended to release the plugin, but didn&#8217;t have time to write some decent documentation, and do a demo project. After reading the comments on the snippet, [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=8&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Several months ago, I posted <a href="http://www.djangosnippets.org/snippets/1389/">this snippet</a> over at <a href="http://www.djangosnippets.org/">Django Snippets</a>. Since then, I&#8217;ve used it a few times, and eventually made it into a jQuery plugin. I always intended to release the plugin, but didn&#8217;t have time to write some decent documentation, and do a demo project.</p>
<p>After reading the comments on the snippet, I finally decided to bite the bullet this weekend, so <a href="http://code.google.com/p/django-dynamic-formset/">here it is</a>. To use it, download one of the releases (I&#8217;d recommend the one with the demo project), unzip it, and check out README.txt and INSTALL.txt.</p>
<h3>Usage</h3>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:0;width:1px;height:1px;">I&#8217;ll assume you&#8217;ve already created your formsets. You can create</div>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:0;width:1px;height:1px;">formsets using any of the provided methods: both regular formsets</div>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:0;width:1px;height:1px;">(created with the &#8220;formset_factory&#8220;) and inline formsets</div>
<div id="_mcePaste" style="position:absolute;left:-10000px;top:0;width:1px;height:1px;">(created with the &#8220;inlineformset_factory&#8220;) are supported.</div>
<p>I&#8217;ll assume you&#8217;ve already created your formsets. You can create formsets using any of the provided methods: both regular formsets (created with the &#8220;formset_factory&#8220;) and inline formsets (created with the &#8220;inlineformset_factory&#8220;) are supported.</p>
<ol>
<li>First, copy jquery.formset.js to your MEDIA_ROOT; don&#8217;t forget to include the jQuery library too!</li>
<li>Include a reference to the script in your template; again, don&#8217;t forget to reference the jQuery library (before the reference to the script).</li>
<li>Render the formset as you normally would &#8212; I usually use a table but you can use DIVs, Ps or whatever you desire. Let&#8217;s use the example markup below:<br />
<pre class="brush: xml;">
&lt;form id=&quot;myForm&quot; method=&quot;post&quot; action=&quot;&quot;&gt;
  &lt;table border=&quot;0&quot; cellpadding=&quot;0&quot; cellspacing=&quot;0&quot;&gt;
    &lt;tbody&gt;
    {% for form in formset.forms %}
      &lt;tr&gt;
        &lt;td&gt;{{ form.field1 }}&lt;/td&gt;
        &lt;td&gt;{{ form.field2 }}&lt;/td&gt;
        &lt;td&gt;{{ form.field3 }}&lt;/td&gt;
      &lt;/tr&gt;
    {% endfor %}
    &lt;/tbody&gt;
  &lt;/table&gt;
  {{ formset.management_form }}
&lt;/form&gt;
</pre></li>
<li>Add the following script to your template (before the closing BODY tag, or in your HEAD, below the reference to jquery.formset.js): <pre class="brush: jscript;">
&lt;script type=&quot;text/javascript&quot;&gt;
  $(function() {
    $('#myForm tbody tr').formset({
      prefix: '{{ formset.prefix }}'
    });
  })
&lt;/script&gt;
</pre>
<p>Notice how our jQuery selector targets the container for each form? We could have assigned a class to each TR and used that instead:</p>
<p><pre class="brush: jscript;">
  $('.form-container-class').formset(...);
</pre></p>
<p>Either way is fine, really :)</li>
<li> That&#8217;s it. Fini. Save your template and navigate to the appropriate view in your application, and you should see an &#8220;add another&#8221; link. Clicking on it should add another instance of your form to the page. You can remove instances by clicking the &#8220;remove&#8221; link; if there&#8217;s only one form in the formset, the remove link isn&#8217;t shown.</li>
</ol>
<h3>License</h3>
<p>This plugin is released under the <a href="http://www.opensource.org/licenses/bsd-license.php">New BSD License</a> &#8211; use it as you wish.</p>
<h3>Quick Download</h3>
<p>For the impatient, you can download the releases here:</p>
<ul>
<li><a href="http://django-dynamic-formset.googlecode.com/files/jquery.formset-1.1.zip">Source code, minified (using jsmin) version and docs</a></li>
<li><a href="http://django-dynamic-formset.googlecode.com/files/jquery.formset-1.1-with-examples.zip">Source code, minified version, docs and demo Django project</a></li>
</ul>
<p>You might also want to check out the <a href="http://code.google.com/p/django-dynamic-formset/">Google Code project</a>.</p>
<p>If you find this useful, feel free to leave a nice comment saying so :) If you find bugs, want to submit a patch, or have an idea for a cool enhancement, submit them to the <a href="http://code.google.com/p/django-dynamic-formset/issues/list">issue tracker</a>.</p>
<h3>Update (3oth Nov, 2009)</h3>
<p><a href="http://elo80ka.wordpress.com/2009/11/30/django-dynamic-formset-v1-1-released/">Version 1.1</a> is now available &#8212; I&#8217;ve updated the download links above to point to it. For details of the changes in 1.1, see the accompanying <a href="http://elo80ka.wordpress.com/2009/11/30/django-dynamic-formset-v1-1-released/">blog post</a>.</p>
<br /> Tagged: Django, jQuery <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/elo80ka.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/elo80ka.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/elo80ka.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/elo80ka.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/elo80ka.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/elo80ka.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/elo80ka.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/elo80ka.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/elo80ka.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/elo80ka.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/elo80ka.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/elo80ka.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/elo80ka.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/elo80ka.wordpress.com/8/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=8&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://elo80ka.wordpress.com/2009/10/10/jquery-plugin-django-dynamic-formset/feed/</wfw:commentRss>
		<slash:comments>34</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f1f096a625c53ca22ee8b57b19724e56?s=96&#38;d=&#38;r=PG" medium="image">
			<media:title type="html">elo80ka</media:title>
		</media:content>
	</item>
		<item>
		<title>Parsing experiments in Python</title>
		<link>http://elo80ka.wordpress.com/2009/10/07/parsing-experiments-python/</link>
		<comments>http://elo80ka.wordpress.com/2009/10/07/parsing-experiments-python/#comments</comments>
		<pubDate>Wed, 07 Oct 2009 21:42:42 +0000</pubDate>
		<dc:creator>elo80ka</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Learning]]></category>
		<category><![CDATA[Parsing]]></category>
		<category><![CDATA[Programming]]></category>
		<category><![CDATA[Python]]></category>

		<guid isPermaLink="false">http://elo80ka.wordpress.com/2009/10/07/parsing-experiments-python/</guid>
		<description><![CDATA[Recently, I&#8217;ve been experimenting with parser generators in Python (we use Python for a lot of our projects at Evince). Previously, I&#8217;d hand-written recursive-descent parsers for simple parsing tasks, but I&#8217;d never felt comfortable enough using them in production code. A couple of weeks ago, Essien showed me Jane &#8211; a toy language he&#8217;d been [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=1&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been experimenting with parser generators in Python (we use Python for a lot of our projects at Evince). Previously, I&#8217;d hand-written recursive-descent parsers for simple parsing tasks, but I&#8217;d never felt comfortable enough using them in production code.</p>
<p>A couple of weeks ago, Essien showed me <a href="http://github.com/essiene/jane">Jane</a> &#8211; a toy language he&#8217;d been developing, which compiled to C. After a few minutes exploring his implementation, I tried to quickly code a backend that generated Python code. My goal wasn&#8217;t really a fully-functional implementation, just to find out how far I could go. I did get it semi-functional &#8211; it choked on nested blocks, because of Python&#8217;s indentation.</p>
<p>Anyways, looking at flex and bison got me thinking &#8220;surely, there&#8217;s got to be stuff like this in Python?&#8221; so I did some googling and came across an <a href="http://onlamp.com/pub/a/python/2006/01/26/pyparsing.html">O&#8217;Reilly article</a> on <a href="http://pyparsing.wikispaces.com/">pyparsing</a>. My test project was an expression parser &#8211; addition, subtraction, multiplication and division, with support for floating-point numbers and variables. After running into problems trying to use pyparsing with recursive productions, I did some more searching and landed on <a href="http://nedbatchelder.com/text/python-parsers.html">this page</a>&#8230;woot!</p>
<p>Eventually, I selected <a href="http://pages.cpsc.ucalgary.ca/~aycock/spark/">SPARK</a> (because it looked interesting) and <a href="http://simpleparse.sourceforge.net">SimpleParse</a> (because it was based on the fast mxTextTools library). I tried out SimpleParse first, and had a parser in minutes &#8211; pretty much the time it took me to type out the grammar. It took a bit longer to generate an AST (mostly time spent studying the documentation, and trying several wrong approaches&#8230;hey, I&#8217;m new at this stuff :), but eventually, I had that done too. Just for good measure, I threw in <a href="http://peak.telecommunity.com/DevCenter/BytecodeAssembler#programmer-api">peak.util.assembler</a> and compiled the AST to Python bytecode, and finally used the &#8220;new&#8221; module to generate a native Python function. Fun!</p>
<p>The next day, I showed all this to Bayo, and suggested he could use it in the payroll application (part of a larger HR application we&#8217;re developing). While discussing his current implementation, he mentioned expressions depending on other expressions, and I thought &#8220;that&#8217;s easy; functions can call other functions, no problem&#8221;. Of course, this meant the parser had to support function calls. I thought &#8220;okay, whatever, I&#8217;ll have a go at it later&#8221;.</p>
<p>At about 2:30 am, I was about to go to bed, and thought I&#8217;d just take a look, and see how much work it&#8217;d be adding support for functions. 3 minutes later, I was done with the implementation &#8211; I added a new production for (no-argument) functions, added a new AST node and modified my compiler to emit the appropriate bytecode for function calls (the &#8220;dis&#8221; module came in pretty handy here). Needless to say, I&#8217;m hooked.</p>
<p>Since then, I&#8217;ve tried to implement a vCard parser (the formal grammar specification for vCard 3.0 is <a href="http://www.ietf.org/rfc/rfc2426.txt">here</a>), port Jane&#8217;s compiler to Python and build a simple template language. I&#8217;ve run into, what I&#8217;d consider limitations of SimpleParse: its inability to specify ignored characters, and it&#8217;s lack of support for back-tracking. Possibly, though, these are as a result of my own inexperience, but I&#8217;d like to try out a few other parser-generators first. Next up: <a href="http://www.dabeaz.com/ply/">PLY</a>.</p>
<br /> Tagged: Learning, Parsing, Programming, Python <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/elo80ka.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/elo80ka.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/elo80ka.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/elo80ka.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/elo80ka.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/elo80ka.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/elo80ka.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/elo80ka.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/elo80ka.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/elo80ka.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/elo80ka.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/elo80ka.wordpress.com/1/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/elo80ka.wordpress.com/1/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/elo80ka.wordpress.com/1/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=elo80ka.wordpress.com&amp;blog=9834401&amp;post=1&amp;subd=elo80ka&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://elo80ka.wordpress.com/2009/10/07/parsing-experiments-python/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/f1f096a625c53ca22ee8b57b19724e56?s=96&#38;d=&#38;r=PG" medium="image">
			<media:title type="html">elo80ka</media:title>
		</media:content>
	</item>
	</channel>
</rss>
