Django, ajax, and forms
2008-12-19
| Comments: 3
I came across a dilemma this evening while using ajax and forms in django. In this article I'll explain a problem with using ajax and django's form framework together, and my solution to that problem. Any suggestions on a better way are certainly welcome.
The Problem
Django's form framework is awesome. You define a form and django handles validation for you. When you click the submit button, the page refreshes and error messages will display automatically for you, like "This field is required". Well tonight I built a login form, that shows up on every page of the site by design. I wanted this form to be able to let the user stay on the same page they are currently on when they login, and display error messages if the form isn't valid etc. My first thought was something like this:
1. Have the form call the login view
2. The view does the login logic.
2. Have the login view redirect them back to the same page they were on, displaying the form.
The problem is then the login form on the page now wouldn't be at all linked to the original form, which means no error-handling for me.
My Solution
This seemed like a good situation for a little ajax. I took all the html/javascript for the login form and put it into its own template called "login.html". In my base.html template I simply {% include "login.html" %} so that the form is displayed in its initial empty state. Here's how things work now:
- User fills in username/password, clicks submit
- Javascript collects the username/password and does an ajax call to my login view.
- The login view does the login logic
- The login view sends the data (via render_to_response) to my login.html form.
- When that form is rendered, that rendering becomes the responseText of my ajax call, so I replace the original form with that data, and voila. Page is updated - and the form shows if there are any errors like it should.
Pros:
Doing ajax calls to forms this way have a few advantages:
- Modularity. This login form with its own separate template can now be used on any site I build.
- Code separation. My base template is now a little cleaner, having separated out the login form functionality.
- Ajax. To put it frankly, ajax is fun. And the entire page doesn't have to reload, making the site feel more "Web 2.0" -- gotta love obscure buzzwords. :)
- Your form can now be used in a good old refresh the whole page kind of way, or in an ajax way.
Cons:
The biggest gotcha I found with doing it this way is that I lose my listeners and have to re-register them. In other words, I have javascript that listens for a click on the "submit" button. It works great the first time. But when the ajax call comes back and sticks new html into the DOM, those listeners aren't even looking at that new submit button, even though it has the same id and everything. So you have to register the click event again after updating the DOM. I decided to do it in the login.html file, just to keep things organized.
So there's my solution for using ajax to make calls to form-handling views. What do you think? Is there perhaps a better way, or at least a more Django-ish way? Comments are welcome.
Comments
uber
4-20-2009 / 10:11 AM
It seems this dude used the same technique for a django-ajax-comment-recaptcha:
http://wwd.ca/blog/2009/03/24/django-ajax-comments-recaptcha/
Maybe this django design pattern should be documented and shrink-wrapped for the people?
“AJAX’d Wordpress (AWP), formerly know as INAP, is an extremely powerful plugin that harnesses the power of AJAX and Wordpress to improve the user experience, the administration capabilities and the design potential of any Wordpress based blog. AWP’s basic features include inline paginated posts, inline comments, threaded comments, the ability to submit comments with AJAX, pagination of your homepage, live comment preview and much more, but it does not, however, force you to use any feature, and it also allows all aspects of the plugin to be easily customized through a single Administration panel. AWP is built to integrate with other plugins and features an advanced module system–based off of WordPress’ plugin system–that allows it to be modified with the addition of third-party extensions. It also has special features that will ensure compatibility with many other plugins.”
the biggest problem i had (most of this takes next to no time) was that initially, my comment form partial used the "Challenge and non-JavaScript API" (scroll down in the reCAPTCHA API doc page to see it), which is what i had used before. But whenever my js would request the partial and then insert it in the empty div, the page would reload to an empty page. Very frustrating. It turns out it's due to something the reCAPTCHA javascript does.