📜 ⬆️ ⬇️

Django - error handling in ajax forms

Hello everyone!

We all know that Django is a very powerful and dynamically developing framework for creating web applications. However, despite the advent of the Web 2.0 era, there are still no built-in mechanisms for working with AJAX , in particular, sending and checking forms. Perhaps django simply does not want to impose some js framework on the user and wants to remain flexible in this matter, but one way or another, development often requires forms that work via ajax, without page reloads.
The creation of such forms and work with them will be discussed in this article.

At once I will make a reservation that the idea is not new, and there are several libraries that implement the required functionality, for example, one of them is http://www.dajaxproject.com/ .
For those who prefer to manage the client’s interaction with the server themselves or those who don’t want to draw an additional library into the project and deal with its bugs, I’ll tell you how to invent a bike to implement the mechanism yourself and describe various ways to solve the problem.

The form


For example, take a simple user registration form on the site:
class RegisterForm(forms.Form): email = forms.EmailField() password1 = forms.CharField(label=_("Password"), widget=forms.PasswordInput) password2 = forms.CharField(label=_("Password confirmation"), widget=forms.PasswordInput) 

In real life, you will most likely inherit this form from the data model, but for our example this is not essential.
')

Form output


To display this form on the page we have two options:

The advantage of the first option is in its speed (no additional requests to the server should be made), but in the second option you can use the same view to process GET and POST requests to the form (we will need POST in both cases), plus we make a separate a template file for form output, which makes the code structure more orderly, although this is of course a matter of taste.
Personally, I embed something in a page template only if it is a simple yes / no dialog, and for forms I always use separate views .
Therefore, we’ll stop here on a separate view for the form, then the code will look like this:

Form processing


We proceed to the processing of the form. Here it is necessary to take into account that the ajax handler must somehow understand whether the form has been successfully verified or contains errors. The logical solution here, in my opinion, is to use JSON . The server response will contain 2 parameters, the first of which is boolean, will report on the success or failure of the validation form. With the second parameter, again, there are various options:
I like the second option ideologically more, because it displays only what is needed, without replacing the entire form. Here I will show how to implement both methods. The client-side form processing code uses the popular jQuery JS framework and its plugin called jQuery Form Plugin .
  1. The first way:

    Final version view :
     def register(request): if request.method == 'POST': form = RegisterForm(request.POST) if form.is_valid(): #  # ... return HttpResponse(simplejson.dumps({'response': _("Email with a confirmation link has been sent"), 'result': 'success'})) else: t = loader.get_template('register.html') ctx = RequestContext(request, {'form': form}) response = t.render(ctx) return HttpResponse(simplejson.dumps({'response': unicode(response), 'result': 'error'})) form = RegisterForm() return direct_to_template(request, "register.html", extra_context={'form': form }) 


    Client-side processing, javascript:
     $(document).ready(function() { $('#register').live('click', function() { $('#register_form').ajaxSubmit({ success: function(data, statusText, xhr, $form) { //     $form.find('.error').remove(); if (data['result'] == 'success') { //  -  } else if (data['result'] == 'error') { //   $form.replaceWith(data['response']); } }, dataType: 'json' }); }); } 
  2. The second way:

    Final version view :
     def register(request): if request.method == 'POST': form = RegisterForm(request.POST) if form.is_valid(): #  # ... return HttpResponse(simplejson.dumps({'response': _("Email with a confirmation link has been sent"), 'result': 'success'})) else: #   response  ,  -   response = {} for k in form.errors: #       ... response[k] = form.errors[k][0] return HttpResponse(simplejson.dumps({'response': response, 'result': 'error'})) form = RegisterForm() return direct_to_template(request, "register.html", extra_context={'form': form }) 


    Client-side processing, javascript:
     function display_form_errors(errors, $form) { for (var k in errors) { $form.find('input[name=' + k + ']').after('<div class="error">' + errors[k] + '</div>'); } } $(document).ready(function() { $('#register').live('click', function() { $('#register_form').ajaxSubmit({ success: function(data, statusText, xhr, $form) { //     $form.find('.error').remove(); if (data['result'] == 'success') { //  -  } else if (data['result'] == 'error') { //   display_form_errors(data['response'], $form); } }, dataType: 'json' }); }); } 
It is also worth noting that when using the second method and the form template described earlier, errors will be displayed using the list item <ul> ; for another display, you need to make a different template or override the error class for the form.

That's all. I attach screenshots of the resulting form in various states:

image

I will be glad to hear comments and learn other ways to work with ajax-forms.

Source: https://habr.com/ru/post/117876/


All Articles