2009-05-15 20 views
8

Tengo un campo de estado que tiene 3 valores: pendiente, activado y rechazado. Si estoy cambiando el valor del estado Deseo tener una verificación activada que no se puede cambiar a pendiente. I no quiero escribir almacenado-procs para esto. ¿Puedo tener el valor anterior en Django antes de guardar?Cómo verificar la transición de valores en Django (django-admin)?

Significa valor nuevo y antiguo.

+0

+1 - Me he estado preguntando lo mismo.En mi caso, hay un trabajo pesado que se hace en un método de guardado que solo es necesario si un campo en un subconjunto particular de los campos del modelo ha cambiado, y he estado buscando una forma de verificar si este es el caso . ¡Gracias! –

Respuesta

10
def clean_status(self): 
    status = self.cleaned_data.get('status') 
    if status == 'pending': 
     if self.instance and self.instance.status == 'activated': 
      raise forms.ValidationError('You cannot change activated to pending') 

    return status 

Este método se debe agregar en una subclase Form. Su nombre es clean_FIELD_NAME.

cleaned_data Contiene valores anteriores. El nuevo valor se almacena en self.instance.

Alternativamente, el método validate() se puede agregar a una subclase forms.Field. See Django documentation.

+0

hey Dominic Rodger puede ayudar en 'inline-django'.Mi pregunta en django – ha22109

8

Puede hacer esto en un método reemplazado save. Lo que hay que recordar es que las instancias del modelo Django no son los objetos reales de la base de datos, solo obtienen sus valores desde allí en carga. De modo que puede volver fácilmente a la base de datos antes de guardar su objeto actual para obtener los valores existentes.

def save(self, *args, **kwargs): 
    if self.status == 'pending': 
     old_instance = MyClass.objects.get(pk=self.pk) 
     if old_instance.status == 'activated': 
       raise SomeError 
    super(MyModel, self).save(*args, **kwargs) 

Actualmente no hay una buena manera de devolver un mensaje de error al usuario que no sea el de generar una excepción. Existe un proyecto Google Summer of Code actualmente en curso para habilitar la 'validación del modelo', pero esto no estará listo durante unos meses.

Si desea hacer algo similar en el administrador, la mejor manera es definir un Modelo de formulario personalizado con un método reemplazado clean(). Sin embargo, esta vez dado que se trata de un formulario, ya tiene acceso a los valores anteriores sin presionar nuevamente el db. Otro beneficio es que puede devolver un error de validación de formulario al usuario.

class MyModelForm(forms.ModelForm): 

    class Meta: 
      model = MyModel 

    def clean_status(self): 
     status = self.cleaned_data.get('status', '') 
     if status == 'pending': 
      if self.instance and self.instance.status == 'activated': 
        raise forms.ValidationError(
         'You cannot change activated to pending' 
       ) 
     return status 

class MyModelAdmin(forms.ModelAdmin): 
    form = MyModelForm 
    model = MyModel 
+0

es porque probablemente deberías anular el método ModelAdmin.save_model: http://docs.djangoproject.com/en/dev/ref/contrib/admin/#modeladmin-methods – ohnoes

+0

He agregado una alternativa usando el administrador anterior. –

+0

la condición if debería ser if self.instance y self.instance.status == 'activated': raise forms.ValidiationError – ha22109

0

En lugar de anular el método guardar, ¿no sería este un buen lugar para usar las señales? Interceptar el guardado antes de la confirmación, verificar el valor actual en la base de datos y reenviar el guardado o rechazarlo.

Ahora no estoy seguro de si la señal bloquea la solicitud de guardado o si ocurre asynch, así que no dude en rechazar esta respuesta si no se puede usar una señal para evitar que ocurra la salvación después de la validación.

Estoy en contra de reemplazar los métodos incorporados si hay otra herramienta incorporada que funciona igual de bien.

+1

Creo que sobrescribir guardar() y eliminar() puede ser una buena práctica. Tengo las clases Foto y Miniatura. El Thumb tiene un elemento = modelos.ForeignKey (Foto). photo.delete() se sobrescribe y borrará todos los pulgares (para t en self.thumbnail_set.all(): t.delete()) antes de ejecutar super (Foto, self) .delete(). Si la extracción del pulgar se hiciera en una señal, el mantenimiento del código sería más difícil. – vikingosegundo

+0

pero __init__ I wolud nunca sobrecargar. Yo usaría señal en su lugar. – vikingosegundo

1

Esto ha sido respondido en otro lugar en Stack Overflow, pero la forma correcta es usar algo como this para rastrear si los campos están sucios. Entonces podrías usar una señal para indicar que algo ha cambiado y que es importante. (es decir, su campo)

0

Encontró este hilo al buscar una respuesta a la misma pregunta. ¿Por qué no hacer algo como esto? De esta manera puede evitar tocar la base de datos. E incorporado __init__ solo un poco extendido. Creo que es mucho más simple que usar señales.

class MyModel(models.Model): 
    my_fair_field = .... 

    def __init__(self, *args, **kwargs): 
     super(MyModel, self).__init__(*args, **kwargs) 
     self.__clean_fair_field = self.my_fair_field 

    def save(self, *args, **kwargs): 
     # check if field value changed 
     if self.__clean_fair_field != self.my_fair_field 
       # ...do some work... 

     super(MyModel, self).save(*args, **kwargs) 
Cuestiones relacionadas