El libro de Django 1.0

7.5. Nuestras propias reglas de validación

Imagina que hemos lanzado al público a nuestro formulario de comentarios, y los correos electrónicos han empezado a llegar. Nos encontramos con un problema: algunos mensajes vienen con sólo una o dos palabras, es poco probable que tengan algo interesante. Decidimos adoptar una nueva póliza de validación: cuatro palabras o más, por favor.

Hay varias formas de insertar nuestras propias validaciones en un formulario de Django. Si vamos a usar nuestra regla una y otra vez, podemos crear un nuevo tipo de campo. Sin embargo, la mayoría de las validaciones que agreguemos serán de un solo uso, y pueden agregarse directamente a la clase del formulario.

En este caso, necesitamos validación adicional sobre el campo message, así que debemos agregar un método clean_message a nuestro formulario:

class ContactForm(forms.Form):
    topic = forms.ChoiceField(choices=TOPIC_CHOICES)
    message = forms.CharField(widget=forms.Textarea())
    sender = forms.EmailField(required=False)

    def clean_message(self):
        message = self.clean_data.get('message', '')
        num_words = len(message.split())
        if num_words < 4:
            raise forms.ValidationError("Not enough words!")
        return message

Este nuevo método será llamado después del validador que tiene el campo por defecto (en este caso, el validador de un CharField obligatorio). Dado que los datos del campo ya han sido procesados parcialmente, necesitamos obtenerlos desde el diccionario clean_data del formulario.

Usamos una combinación de len() y split() para contar la cantidad de palabras. Si el usuario ha ingresado muy pocas palabras, lanzamos un error ValidationError. El texto que lleva esta excepción se mostrará al usuario como un elemento de la lista de errores.

Es importante que retornemos explícitamente el valor del campo al final del método. Esto nos permite modificar el valor (o convertirlo a otro tipo de Python) dentro de nuestro método de validación. Si nos olvidamos de retornarlo, se retornará None y el valor original será perdido.