Implementando jQuery Tag Inputs en Django, Parte 2

Ayer comencé un artículo sobre cómo implementar en Django el plugin de Jquery Tag Inputs, usado por Tumblr, y nos centramos en cómo mostrar las etiquetas que ya tenemos guardadas a la hora de editarlas como campo ManyToManyField.

Hoy nos centraremos en cómo validar y limpiar los datos para guardarlos en la base de datos. Para ello lo primero es crear una clase que herede de ModelMultipleChoiceField, ya que hemos cambiado el widget asociado a éste por defecto (hemos puesto un Textarea), y en el formulario al hacer submit el campo Field para este elemento se va a encontrar con una cadena en vez de con una lista al validar y devolver los datos correctos.

Este proceso de validación se lleva a cabo en la función clean dentro de cualquier clase del tipo Field de Django. Como Tag Inputs define separación de comas entre tags y nos devuelve un string, comenzaríamos haciendo un split de los datos obtenidos, para posteriormente y basándonos en el código de ModelMultipleChoiceField original, cambiar la variable value que se usa en todo el método por nuestra variable (yo la he llamado value_splitted).

La clase quedaría de la siguiente manera:


class MyModelMultipleChoiceField(ModelMultipleChoiceField):

    def clean(self, value):
        value_splitted = value.split(",")

        if self.required and not value_splitted:
            raise ValidationError(self.error_messages['required'])
        elif not self.required and not value_splitted:
            return []
        if not isinstance(value_splitted, (list, tuple)):
            raise ValidationError(self.error_messages['list'])

        key = "slug"
        qs = self.queryset.filter(**{'%s__in' % key: value_splitted})
        # we run custom validators here
        self.run_validators(value_splitted)
        return qs

El Field por defecto no te deja elegir una etiqueta que previamente no esté en la base de datos(fallaría la validación), yo necesitaba que todas las etiquetas pasasen el filtro independientemente de que estuviesen en la base de datos, con lo que eliminé esas líneas. También modifiqué el atributo con el que tomar las etiquetas de la bd, uso un campo slug en vez del id.

Todavía se puede arreglar más el clean (como comprobar si el value es vacío antes de hacer el split), pero nos sirve de ejemplo plenamente funcional. :-)

Finalmente en nuestra clase Form para el modelo correspondiente cambiamos la clase ModelMultipleChoiceField por nuestra clase.

Javier Aguirre

Read more posts by this author.

comments powered by Disqus