2012-09-05 19 views
14

Tengo un problema con el método clean() de un modelo y la validación básica del campo. aquí está mi modelo y el método clean().método clean() en validación de modelo y campo

class Trial(models.Model): 

    trial_start = DurationField() 
    movement_start = DurationField() 
    trial_stop = DurationField() 


    def clean(self): 
     from django.core.exceptions import ValidationError 
     if not (self.movement_start >= self.trial_start): 
      raise ValidationError('movement start must be >= trial start') 
     if not (self.trial_stop >= self.movement_start): 
      raise ValidationError('trial stop must be >= movement start') 
     if not (self.trial_stop > self.trial_start): 
      raise ValidationError('trial stop must be > trial start') 

Mis clean() método comprueba si ciertos valores están en el rango correcto. Si el usuario olvida completar un campo, p. movement_start, entonces me da un error:

can't compare datetime.timedelta to NoneType

me sorprende que me sale este error, ya que la función original clean() debe ponerse al que falta la entrada (después de todo movement_start es un campo obligatorio). Entonces, ¿cómo puedo hacer una verificación básica de los valores perdidos, y mi verificación personalizada si los valores están en ciertos rangos? ¿Se puede hacer esto con el método clean() de la modelo, o necesito usar Forms?

EDIT1 a hacer más claro: trial_start, movement_start y trial_stop son todos los campos requeridos. Necesito escribir un método clean() que compruebe primero que se hayan completado los tres campos y luego, verifique si los valores están en un cierto rango.

El siguiente código, por ejemplo, NO funciona, ya que trial_start podría estar vacío. Quiero evitar tener que verificar la existencia de cada campo; django debería hacer eso por mí.

class TrialForm(ModelForm): 

    class Meta: 
     model = Trial 

    def clean_movement_start(self): 
     movement_start = self.cleaned_data["movement_start"] 
     trial_start = self.cleaned_data["trial_start"] 
     if not (movement_start >= trial_start): 
      raise forms.ValidationError('movement start must be >= trial start') 
     return self.cleaned_data["movement_start"] 

Edit2 La razón por la que quería añadir este control con el método del modelo clean() es que los objetos que se crean en el intérprete de Python, automáticamente serán comprobados por los valores correctos. Un formulario estará bien para las vistas, pero necesito la verificación de valor también para el shell.

+0

Añadir 'blank = false' para hacer campos obligatorios. –

+0

@BurhanKhalid los campos son obligatorios. 'blank = False' es el valor predeterminado. – memyself

+0

@JonasGeiregat, entonces debería usar 'Forms' en su lugar? – memyself

Respuesta

6

supongo que es el camino a seguir:

class TrialForm(ModelForm): 

    class Meta: 
     model = Trial 

    def clean(self): 

     data = self.cleaned_data 
     if not ('movement_start' in data.keys() and 'trial_start' in data.keys() and 'trial_stop' in data.keys()): 
      raise forms.ValidationError("Please fill out missing fields.") 

     trial_start = data['trial_start'] 
     movement_start = data['movement_start'] 
     trial_stop = data['trial_stop'] 

     if not (movement_start >= trial_start): 
      raise forms.ValidationError('movement start must be >= trial start') 

     if not (trial_stop >= movement_start): 
      raise forms.ValidationError('trial stop must be >= movement start') 

     if not (trial_stop > trial_start): 
      raise forms.ValidationError('trial stop must be > trial start') 

     return data 

EDITAR la desventaja de este enfoque es que la comprobación de valores sólo funcionará si puedo crear objetos a través del formulario. Los objetos que se crean en el shell de python no serán verificados.

0

Estoy luchando con un problema similar pero con un ForeignKey. En su caso, me acaba de comprobar que los campos no están vacíos, y me simplificar las expresiones booleanas:

class Trial(models.Model): 

    trial_start = DurationField() 
    movement_start = DurationField() 
    trial_stop = DurationField() 


    def clean(self): 
     from django.core.exceptions import ValidationError 
     if self.trial_start: 
      if self.movement_start and self.movement_start < self.trial_start: 
       raise ValidationError('movement start must be >= trial start') 
      if self.trial_stop: 
       if self.trial_stop <= self.trial_start: 
        raise ValidationError('trial stop must be > trial start') 
       if self.movement_start: 
        if self.trial_stop < self.movement_start: 
         raise ValidationError('trial stop must be >= movement start') 
2

Sé que es tarde, pero a responder por qué esto podría estar sucediendo para las personas que terminan aquí : No hay "limpieza original". El método de limpieza es un gancho para la validación personalizada, por lo que usted es quien proporciona su código. No estoy seguro de cómo OP estaba utilizando el gancho limpio, pero: Después de definirlo, debe llamar al full_clean() sobre sus modelos para que Django ejecute la validación del modelo en su totalidad.Consulte los detalles en los documentos para el orden en que llama a los diferentes métodos de validación y https://docs.djangoproject.com/en/1.11/ref/models/instances/#validating-objects (tal vez es importante tener en cuenta: full_clean() no es llamado automáticamente por el modelo save() que es parte de por qué cuando usa el shell y guarda de inmediato que va a saltarse la validación)

(ModelForms nota también tienen diversas etapas de validación y llamarán a full_clean de un modelo: https://docs.djangoproject.com/en/1.11/topics/forms/modelforms/#validation-on-a-modelform)

Cuestiones relacionadas