tutorial example decimalfield custom choices python django django-models

python - custom - decimalfield django example



ValidaciĆ³n de los campos modelo Django (4)

¿Dónde debe ir la validación de los campos del modelo en django?

Podría nombrar al menos dos opciones posibles: en el método .save () sobrecargado del modelo o en el método .to_python () de los modelos. Subclase de campos (obviamente, para que eso funcione, debe escribir campos personalizados).

Posibles casos de uso:

  • cuando sea absolutamente necesario garantizar que una cadena vacía no se escriba en la base de datos (en blanco = El argumento de palabra clave False no funciona aquí, solo para la validación de formularios)
  • cuando sea necesario garantizar que el argumento de la palabra clave "elecciones" se respete en un nivel db y no solo en la interfaz administrativa (tipo de emulación de un tipo de datos enum)

También hay un atributo de nivel de clase empty_strings_allowed en los modelos. La definición de clase base de campo y las clases derivadas lo anulan alegremente, sin embargo, no parece producir ningún efecto en el nivel de base de datos, lo que significa que aún puedo construir un modelo con cadena vacía campos y guardarlo en la base de datos. Lo cual quiero evitar (sí, es necesario).

Posibles implementaciones son

en el nivel de campo:

class CustomField(models.CharField): __metaclass__ = models.SubfieldBase def to_python(self, value): if not value: raise IntegrityError(_(''Empty string not allowed'')) return models.CharField.to_python(self, value)

en el nivel modelo:

class MyModel(models.Model) FIELD1_CHOICES = [''foo'', ''bar'', ''baz''] field1 = models.CharField(max_length=255, choices=[(item,item) for item in FIELD1_CHOICES]) def save(self, force_insert=False, force_update=False): if self.field1 not in MyModel.FIELD1_CHOICES: raise IntegrityError(_(''Invalid value of field1'')) # this can, of course, be made more generic models.Model.save(self, force_insert, force_update)

Tal vez, me falta algo y esto se puede hacer más fácil (y más limpio)?


Creo que quieres esto ->

from django.db.models.signals import pre_save def validate_model(sender, **kwargs): if ''raw'' in kwargs and not kwargs[''raw'']: kwargs[''instance''].full_clean() pre_save.connect(validate_model, dispatch_uid=''validate_models'')

(Copiado de http://djangosnippets.org/snippets/2319/ )


Django tiene un sistema de validación de modelos implementado desde la versión 1.2.

En comentarios, sebpiq dice "Ok, ahora hay un lugar para poner la validación del modelo ... ¡excepto que se ejecuta solo cuando se utiliza un ModelForm! Así que queda la pregunta, cuando es necesario garantizar que la validación se respete en el nivel db , ¿qué deberías hacer? ¿Dónde llamar a full_clean? "

No es posible a través de la validación a nivel de Python garantizar que se respete la validación en el nivel de db. Lo más probable es que llame a full_clean en un método save anulado. Esto no se hace de manera predeterminada, porque significa que todos los que llaman a ese método de guardar ahora deben estar preparados para capturar y manejar ValidationError .

Pero incluso si hace esto, alguien aún puede actualizar las instancias del modelo a granel utilizando queryset.update() , lo que queryset.update() esta validación. No hay forma de que Django pueda implementar un queryset.update() razonablemente eficiente que aún pueda realizar la validación a nivel de Python en cada objeto actualizado.

La única forma de garantizar realmente la integridad del nivel db es a través de restricciones de nivel db; cualquier validación que realice a través del ORM requiere que el redactor del código de la aplicación tenga en cuenta que se aplique la validación (y que maneje los fallos de validación).

Esta es la razón por la que la validación del modelo solo se aplica de manera predeterminada en ModelForm , porque en un ModelForm ya existe una forma obvia de manejar un ValidationError .


El problema principal para esto, es que la validación debería ocurrir en los modelos. Esto se ha discutido durante bastante tiempo en django (validación basada en el modelo de formulario de búsqueda en la lista de distribución de correo dev). Conduce a la duplicación o a cosas que escapan de la validación antes de llegar al db.

Si bien eso no afecta al tronco, la "solución de validación del modelo de hombre pobre" de Malcolm es probablemente la solución más limpia para evitar repetirse.


Si te entiendo "claramente" - debes anular la función get_db_prep_save en lugar de to_python