Reputation: 107272
I'm trying to create a page with two functional parts:
I'm using django forms and jQuery and I can't quite figure out how the design fits together.
Upon submission of the form one of two things should happen, either the chart (and only the chart) updates or, if there is a form validation error, the form section should update with the appropriate error messages. So actually one Ajax call should update either part.
I'd like only the relevant div
to update (either form or chart) instead of the entire page which includes the other div
, a logo and other static graphics.
One of the challenges is that if the form sumbission went well, I'd like to return a JSON object which updates the chart, as I'm using a 3rd party charting package, however if the submission failes the returned content should be an HTML response with the updated form.
What would be a correct pattern for the django view for this behavior?
What would be a correct javascript\jQuery pattern for this behavior?
If this approach is not correct, what would be an alternative approach?
Upvotes: 2
Views: 3976
Reputation: 906
There is a nice article about this. It really describes the design of AJAX forms with Django. There are all basic stuff there, that you might need in a while. Like AJAX error handling, jQuery basic forms plugin usage and events handling. Also accent is on connecting exactly Django backend and jQuery.form frontend. Here it is. http://garmoncheg.blogspot.com/2013/11/ajax-form-in-django-with-jqueryform.html
Upvotes: 0
Reputation: 33420
You need JavaScript. For example, with jQuery:
$('form').submit(function() {
$.post($(this).attr('action'), $(this).serialize(), function(data, textStatus, jqXHR){
if (typeof data == 'object') {
// json was returned, update the chart with the json
} else {
// the form had error, the form's html was returned
$('form').html(data);
}
})
})
You can have such a python view:
from django.utils import simplejson
from django import shortcuts
def chart_form(request):
template_full = 'chart_full.html' # extends base.html etc ..
template_form = 'chart_form.html' # just the form, included by chart_full.html
if request.method == 'POST':
form = formClass(request.POST)
if form.is_valid():
// do your chart_data
chart_data = ....
return http.HttpResponse(simplejson.dumps(chart_data), mimetype='application/json')
else:
form = formClass()
if request.is_ajax():
template_name = template_form
else:
template_name = template_full
return shortcuts.render(template_name, {'form': form}, request)
Note: that won't work if your form contains file fields. In that case, rely on this plugin: http://jquery.malsup.com/form/ (function ajaxSubmit)
Upvotes: 1
Reputation: 31683
Why not return JSON with validation errors when form contains invalid data? Django has a Form.errors fields which contains validation errors for each field. These field can easily be converted to JSON and used to mark your inputs invalid:
Your view:
def submit_form_view(request):
if request.method == 'POST': # If the form has been submitted...
form = ChartForm(request.POST)
if form.is_valid(): # All validation rules pass
# Return JSON response if form was OK
response_data = {'form_saved':True, 'data':'somedata'}
return HttpResponse(json.dumps(response_data), mimetype="application/json")
else: # Invalid data:
# Send what were errors
response_data = {'form_saved': False, 'errors': form.errors}
return HttpResponse(json.dumps(response_data), mimetype="application/json")
else:
form = ChartForm() # An unbound form
return render_to_response('contact.html', {
'form': form,
})
Javascript code:
$.ajax({
url: '{% url someapp.submit_form_view %}',
success: function(data) {
if( data.form_saved ){
$('#form input').removeClass('error'); // Form submit ok -> remove error class of all fields
var chart_data = data.chart_data;
// Update the chart here
}else{
var form_errors = data.form_errors;
// Display form validation errors
for(var fieldname in form_errors) {
var errors = form_errors[fieldname]; // Array of error strings for fieldname
$('#form input[name="'+fieldname+']').addClass('error')
}
}
}
});
Upvotes: 1