Ok - the basics. First thing you need to understand - when talking about ajax here we mean a request which is sent from the browser by javascript, usually asynchronously ( meaning user can do other things while we're processing it). So to keep it simple - ajax is the 'request' we're using in our django views. And instead of reloading the whole page after user clicks some link or submits form we can first process it in the background and then refresh only the needed parts of the page. Sounds pretty facebookish doesn't it ? :) And there's no magic in it, really.
Let's start from the simplest possible example - we will allow user to add email to some newsletter. Here is tho code for model, url and form :
class NewsletterForm(forms.Form): email = forms.EmailField(label=_("E-mail address")) class NewsletterEmails(models.Model): email = models.EmailField(_(u"E-mail address"),) urlpatterns = patterns('', url(r'^newsletter_add/$', newsletter_add, name="newsletter_add"), )
Nothing unexpected here I guess. Simple model, simple form with just one field and a link to our view (remember - even though we're not redirecting user to this link, we still need a way to call our view function processing the email).
Next comes the view function :
from django.http import HttpResponse from django.template.loader import render_to_string from django.utils import simplejson from django.utils.functional import Promise from django.utils.encoding import force_unicode from models import NewsletterEmails from forms import NewsletterForm #here is some magic. We need to write custom JSON encoder, since sometimes #serializing lazy strings can cause errors. #You need to write it only once and then can reuse in any app class LazyEncoder(simplejson.JSONEncoder): """Encodes django's lazy i18n strings. """ def default(self, obj): if isinstance(obj, Promise): return force_unicode(obj) return obj #here the view function starts def newsletter_add(request): #as usual when processing forms we check if the method was POST/GET if request.method == "POST": #we get email address from request variables adr = request.POST['email'] e = None #we process address only if it's longer than 6 characters. #this assures us than we won't waste server time on #addresses like 'oeui' or 'u@u.u' if len(adr) > 6: #create form instance and fill it with data. In this case it will only be the email address form = NewsletterForm(data=request.POST) #let django perform the validation if form.is_valid(): #check if the email address is not already in our database try: e = NewsletterEmails.objects.get(email = adr) message = _(u"Email already added.") type = "error" except NewsletterEmails.DoesNotExist: if DoesNotExist exception was caught we add the address 'safe-mode' using try/catch try: e = NewsletterEmails(email = adr) except DoesNotExist: pass message = _(u"Email added.") type = "success" e.save() else: message = _(u"Bad address.") type = "error" else: message = _(u"Too short address.") type = "error" #we don't need to do this but it's good practice to check the source of request. If it comes from ajax call we build the response. if request.is_ajax(): #let built in simplejson package serialize our data. It means we transform everything to simple strings. result = simplejson.dumps({ "message": message, "type": type, }, cls=LazyEncoder) #return the response return HttpResponse(result, mimetype='application/javascript')
Now the form. This is really basic so I won't say anything more about it apart of the fact that we explicitly set the action of our form to address of view processing addition of emails :
and finally the javascript part. I'm using jQuery javascript library here as well as jQuery's form plugin for processing forms. It simply adds method that takes all the values from form's fields and sends it to specified address (in this case it'll be "newsletter_add"). We could do this by ourselves, but that's not what this tutorial is about.
And basically that will be all for this part. As you can see the key to using AJAX with django is that our views must return serialized strings with JSON so that we can process them with javascript.
For the first time I have prepared a working example under this link :
http://samples.fromzerotocodehero.x14.eu/newsletter1/start
as well as downloadable code :
http://ofcjs.x14.eu/ajax1.zip
If you have any questions feel free to ask in comments or on my twitter.
Hey there owca,
ReplyDeletethanks for your crystal clear explanation, and such a useful simple script... well done!
You need to prefix DoesNotExist on line 52 with:
ReplyDeleteNewsletterEmails.
Muchas gracias, funciona perfecto. Tuve que hacer algunas modificaciones pero funcion OK ;)
ReplyDeleteHi, I´m trying to run the code but doesn't work, when the post sends I get a 403 error.. can you help me please?
ReplyDeleteI'm using django 1.3.1
thanks alot
Firstly, I wish to see syntax highlighting..
ReplyDeletethanks for the explanation
ReplyDeletei wrote my code based on yours and it works fine, the only thing is a deprecated alert on the use of simplejson
Hey. Its probably a django noob thing (though I have made a couple of sites in django 1.5), but it is not exactly self explanatory the names of the files you are using, imports, etc. I was hoping to grab the working project but the link is down. Does anyone have this?
ReplyDelete