Mixed code -- Sorry about that. urls.py === #Direct to template: For non-ajax form. (r'afterform/$', 'django.views.generic.simple.direct_to_template', {"template": 'contact/afterform.html',"extra_content":{"error":False} }), #Handle contact form. Using a named url: Note use in template below. #This url handles contact/ and contact/xhr : The 'xhr' is a flag to tell the #view that this is an ajax POST. I can't recall what it stood for :) url(r'contact/(?P.*)$', 'scents.contact.views.contactForm',name='contactform'), views.py === from django.shortcuts import render_to_response from django.http import HttpResponseRedirect, HttpResponse from django import forms from django.template import RequestContext from django.utils import simplejson # This describes our "form" - on the server side. class ContactForm( forms.Form ): subject = forms.CharField(label = "Subject",max_length=80) text = forms.CharField(label = "Your query",widget=forms.Textarea) class Media: # Plug in the javascript we will need: js = ("/media/js/jquery/jquery-1.2.6.pack.js", "/media/js/jquery/plugins/form/jquery.form.js") # The main view: def contactForm( request, xhr="WTF?" ): #The xhr default is being ignored. Weird. # Is this a POST? if request.method == "POST": form = ContactForm(request.POST) #Check if the var had something passed to it. if xhr=="xhr": # Yup, this is an Ajax request. # Validate the form: clean = form.is_valid() # Make some dicts to get passed back to the browser rdict = {'bad':'false'} if not clean: rdict.update({'bad':'true'}) d={} # This was painful, but I can't find a better way to extract the error messages: for e in form.errors.iteritems(): d.update({e[0]:unicode(e[1])}) # e[0] is the id, unicode(e[1]) is the error HTML. # Bung all that into the dict rdict.update({'errs': d }) # Make a json whatsit to send back. json = simplejson.dumps(rdict, ensure_ascii=False) # And send it off. return HttpResponse( json, mimetype='application/javascript') # It's a normal submit - non ajax. else: if form.is_valid(): # Move on to an okay page: return HttpResponseRedirect("/scents/afterform/") else: # It's not post so make a new form form = ContactForm()#error_class=DivErrorList) # Get it rollin: return render_to_response( 'contact/contact.html', { "form":form, }, context_instance=RequestContext(request) ) contact.html (The template) === {% extends "base.html" %} {% block J%}{{form.media}}{% endblock %} {% block CSS %}forms.css{%endblock%} {% block JQUERY %} // prepare the form when the DOM is ready $(document).ready(function() { // prepare Options Object var options = { url: '{% url contactform "xhr"%}', // Here we pass the xhr flag dataType: 'json', success: processJson, //What to call after a reply from Django beforeSubmit: beforeForm }; // bind form using ajaxForm $('#tf').ajaxForm(options); //My form id is 'tf' }); function beforeForm() { $('#bt').attr("disabled","disabled"); //Disable the submit button - can't click twice $('.errorlist').remove(); //Get rid of any old error uls $('#emsg').fadeOut('slow'); //Get rid of the main error message return true; //Might not need this... } #Do stuff with server reply: function processJson(data) { // This is the first time I have touched jQuery, so I'm not sure about my // approach. It does work, but perhaps not in the best way. //Do we have any data at all? if (data) { // Build a var. NOTE: Make sure your id name (this is a div) is NOT THE SAME // as any var in javascript -- ie has a fit and barfs errors. e_msg = "We received your form, thank you."; // Did we set the 'bad' flag in Django? // Use eval() to turn the stuff in the data object into actual vars. if (eval(data.bad)) { e_msg = "Please check your form."; errors = eval(data.errs); //Again with the eval :) // This is very nice: Go thru the errors, build an id name and // then access that tag and add the HTML from the Django error $.each(errors,function(fieldname,errmsg) { id = "#id_" + fieldname; $(id).parent().before( errmsg ); //I want the error above the

holding the field }); // re-enable the submit button, coz user has to fix stuff. $('#bt').attr("disabled",""); } //Show the message $('#emsg').text( e_msg ).fadeIn("slow"); } else { //DON'T PANIC :D $('#emsg').text("Ajax error : no data received. ").fadeIn("slow"); } } {% endblock %} {% block CONTENT %}

 
{{ form.as_p }}
{% endblock %} Conclusion === Right, that's it. I hope. If I didn't make any horrible mistakes in writing this small tut then you should be able to reproduce the effect. HTH \d