views:

178

answers:

3

How do I design a Django/Javascript application to provide for conditional Ajax responses to conventional HTTP requests?

On the server, I have a custom-built Form object. When the browser POSTS the form's data, the server checks the submitted data against existing data and rules (eg, if the form adds some entity to a database, does that entity already exist in the database?). If the data passes, the server saves, generates an ID number and adds it to the form's data, and passes the form and data back to the browser.

if request.method == 'POST':
    formClass = form_code.getCustomForm()
    thisForm = formClass(data=request.POST)
    if thisForm.isvalid():
        saveCheck = thisForm.saveData()
        t = loader.get_template("CustomerForm.html")
        c = Context({ 'expectedFormObj': thisForm })

(Note that my custom logic checking is in saveData() and is separate from the html validation done by isvalid().)

So far, standard Django (I hope). But if the data doesn't pass, I want to send a message to the browser. I suppose saveData() could put the message in an attribute of the form, and the template could check for that attribute, embed its data as javascript variable and include a javascript function to display the message. But passing all that form html back, just to add one message, seems inelegant (as does the standard Django form submission process, but never mind). In that case I'd like to just pass back the message.

Now I suppose I could tie a Javascript function to the html form's onsubmit event, and have that issue an XMLHttpRequest, and have the server respond to that based on the output of the saveData() call. But then the browser has two requests to the server outstanding (POST and XHR). Maybe a successful saveData() would rewrite the whole page and erase any potential for conflict. But I'd also have to get the server to sequence its response to the XHR to follow the response to the POST, and figure out how to communicate the saveData outcome to the response to the XHR. I suppose that is doable, even without the thread programming I don't know, but it seems messy.

I speculate that I might use javascript to make the browser's response conditional to something in the response to the POST request (either rewrite the whole page, or just display a message). But I suspect that the page's javascript hands control over the browser with the POST request, and that any response to the POST would just rewrite the page.

So can I design a process to pass back the whole form only if the server-side saveData() works, and a message that is displayed without rewriting the entire form if saveData() doesn't? If so, how?

A: 

FYI, this isn't an answer...but it might help you think about it a different way

Here's the problem I'm running into...http://stackoverflow.com/questions/1292111/google-app-engine-jquery-ajax-405-method-not-allowed.

So basically I get the thing to work using the outlined code, then I can't make the AJAX request :(.

farina
+3  A: 

Although you can arrange for your views to examine the request data to decide if the response should be an AJAXish or plain HTML, I don't really recommend it. Put AJAX request handlers in a separate URL structure, for instance all your regular html views have urls like /foo/bar and a corresponding api call for the same info would be /ajax/foo/bar.

Since most views will examine the request data, then do some processing, then create a python dictionary and pass that to the template engine, you can factor out the common parts to make this a little easier. the first few steps could be a generic sort of function that just returns the python dictionary, and then actual responses are composed by wrapping the handler functions in a template renderer or json encoder.

My usual workflow is to initially assume that the client has no javascript, (which is still a valid assumption; many mobile browsers have no JS) and implement the app as static GET and POST handlers. From there I start looking for the places where my app can benefit from a little client side scripting. For instance I'll usually redesign the forms to submit via AJAX type calls without reloading a page. These will not send their requests to the same URL/django view as the plain html form version would, since the response needs to be a simple success message in plain text or html fragment.

Similarly, getting data from the server is also redesigned to respond with a concise JSoN document to be processed into the page on the client. This also would be a separate URL/django view as the corresponding plain html for that resource.

TokenMacGuy
Thanks -- as I posted, the whole thing sounded like a bad idea. Two questions. 1) I am but an egg, and do not grok "API call". Would that refer here to a call by Ajax functions? 2) As I understand the second paragraph, the server would resend all the html for the form, with additional bits as appropriate. Yes?
chernevik
+2  A: 

When dealing with AJAX, I use this:

from django.utils import simplejson
...
status = simplejson.dumps({'status': "success"})
return HttpResponse(status, mimetype="application/json")

Then, AJAX (jQuery) can do what it wants based on the return value of 'status'.

I'm not sure exactly what you want with regards to forms. If you want an easier, and better form experience, I suggest checking out uni-form. Pinax has a good implementation of this in their voting app.

Adam Nelson