Cómo usar mixins para procesar formularios AJAX en Django
Vera Mazhuga
Software DeveloperDjango es un framework de Python poderoso, pero desgraciadamente no ofrece solución alguna para procesar los formularios usando AJAX: enviar los datos al servidor, volver el listado de errores si los datos no habían pasado la validación.
Procesar los formularios con AJAX tiene unas ventajas: no es necesario recargar la página, ni renderizar todo el formulario de nuevo. Vamos a mirar como se puede validar los formularios usando Django y AJAX.
En Internet hay muchos ejemplos de cómo devolver los datos en el formato JSON desde la vista, pero aquí vamos a mover toda la lógica a un mixin. Esto va a permitirnos escribir todas nuestras vistas sin ninguna lógica adicional. Para nuestro ejemplo vamos a usar las vistas basadas en clases.
Describimos los pasos con más detalle:
- Creamos una clase del formulario muy sencillo de Django, basada en un modelo que se llama
Comment
:
Escribimos una vista basada en clases que se dedica a crear nueva instancia del modelofrom django import forms from django.db import models class Comment(models.Model): created_at = models.DateTimeField( verbose_name=u'Date', auto_now_add=True, ) message = models.TextField( verbose_name=u'Message', ) class CommentForm(forms.Form): class Meta: model = Comment
Comment
:
Como se puede notar, este formulario aparte de la clasefrom django.views.generic import CreateView class CommentCreateView(JSONFormMixin, CreateView): model = Comment form_class = CommentForm
CreateView
hereda un mixinJSONFormMixin
.Vamos a verlo con mayor detalle:class JSONMixin(object): def render_to_response(self, context, **httpresponse_kwargs): return self.get_json_response( self.convert_context_to_json(context), **httpresponse_kwargs< ) def get_json_response(self, content, **httpresponse_kwargs): return HttpResponse( content, content_type='application/json', **httpresponse_kwargs ) def convert_context_to_json(self, context) u""" Este método serializa un formulario de Django y retorna un objeto JSON con sus campos y errores """ form = context.get('form') to_json = {} options = context.get('options', {}) to_json.update(options=options) to_json.update(success=context.get('success', False)) fields = {} for field_name, field in form.fields.items(): if isinstance(field, DateField) \ and isinstance(form[field_name].value(), datetime.date): fields[field_name] = \ unicode(form[field_name].value().strftime('%d.%m.%Y')) else: fields[field_name] = \ form[field_name].value() \ and unicode(form[field_name].value()) \ or form[field_name].value() to_json.update(fields=fields) if form.errors: errors = { 'non_field_errors': form.non_field_errors(), } fields = {} for field_name, text in form.errors.items(): fields[field_name] = text errors.update(fields=fields) to_json.update(errors=errors) return json.dumps(to_json)
De forma predeterminada las vistas de Django vuelven la información en el formato text/html. Para cambiar este comportamiento, reescribimos el método
render_to_response
para que devuelva el objeto JSON. Luego, tenemos que redefinir el métodoconvert_context_to_json
, para indicar cómo procesar el objeto del formulario.En nuestro caso tenemos que obtener el formulario
context.get('form')
y formar desde sus atributos un diccionarioto_json
, que después vamos a devolver al cliente, convirtiéndolo previamente al formato JSONjson.dumps(to_json)
. El diccionarioto_json
va a tener la siguiente estructura:{ fields: { message: 'contenido del campo message', }, errors: { non_field_errors: 'errores no relacionados con algún campo específico', fields: { message: 'errores relacionados con el campo message' } } options: { }, // parámetros adicionales que queremos devolver al cliente success: false // o true si el formulario es válido }
Como podemos ver, ahora tenemos todos los datos, que normalmente
CreateView
de Django devuelve a la plantilla, en el formato JSON.
- Ahora podemos pintar nuestro formulario en la plantilla:
id="add_comment_submit" class="btn"<form id="add_comment_form" method="post" action="{% url 'comment_create' %}">{% csrf_token %} {{ comment_form }} <a id="add_comment_submit" class="btn">Send
El siguiente paso será escribir una función de JavaScript que va a capturar el evento "submit" del formulario, serializa todos los datos diligenciados, los envía a nuestra vista
CommentCreateView
y procesa la respuesta.$('#add_comment_submit').click(function() { $.ajax({ url: $('#add_comment_form').attr('action'), type: 'POST', data: $('#add_comment_form').serialize(), dataType: 'json', success: function(response) { if(response.success){ $('#add_comment_form')[0].reset(); $('.form-error').remove(); $('#comments').prepend(response.fields.message); } else { $('.form-error').remove(); for(var error in response.errors.fields) { $('#add_comment_form #id_' + error).before('<div class="form-error">' + response.errors.fields[error] + '</div>'); } } } }); });
En caso de éxito el algoritmo primero revisa si el formulario es válido o no. En caso de ser válido, limpia todos los campos del formulario y los errores en caso de que antes hubiese pintados y agrega el mensaje al listado de comentarios. Si los datos tienen errores, en el bucle vamos por todos los campos del formulario y agregamos el texto del error correspondiente.
Para simplificar el manejo de formularios en JavaScript se puede usar el plugin jQuery Form.
Al final tenemos un mixin, que nos permite procesar los formularios de Django con facilidad y devolver los datos en el formato JSON, que podemos usar para todos nuestros formularios que necesiten validación vía AJAX.
Written by Vera Mazhuga
Vera specializes in writing and maintaining code for various applications. Her focus on problem-solving and efficient programming ensures reliable and effective software solutions.