type form def clean __str__ python django django-models django-validation

python - form - ¿Por qué el model.save() de django no llama a full_clean()?



type models django (5)

AFAIK, esto se debe a la compatibilidad con versiones anteriores. También hay problemas con ModelForms con campos excluidos, modelos con valores predeterminados, señales pre_save (), etc.

Fuentes en las que puede estar interesado:

Solo tengo curiosidad si alguien sabe si hay buenas razones para que el orm de django no llame a ''full_clean'' en un modelo a menos que se guarde como parte de un formulario de modelo.

Tenga en cuenta que full_clean () no se invocará automáticamente cuando llame al método save () de su modelo. Tendrá que llamarlo manualmente cuando desee ejecutar la validación del modelo de un solo paso para sus propios modelos creados manualmente. doc completo de django

(NOTA: cita actualizada para Django 1.6 ... los documentos anteriores de django también tenían una advertencia sobre ModelForms).

¿Hay buenas razones por las cuales las personas no desearían este comportamiento? Creo que si se tomó el tiempo de agregar validación a un modelo, querría que se ejecutara esa validación cada vez que se guarde el modelo.

Sé cómo hacer que todo funcione correctamente, solo estoy buscando una explicación.


Debido a la compatibilidad, la limpieza automática al guardar no está habilitada en django kernel.

Si estamos comenzando un nuevo proyecto y queremos que el método de save predeterminado en Model se pueda limpiar automáticamente, podemos usar la siguiente señal para limpiar antes de guardar cada modelo.

from django.dispatch import receiver from django.db.models.signals import pre_save, post_save @receiver(pre_save) def pre_save_handler(sender, instance, *args, **kwargs): instance.full_clean()


En lugar de insertar un fragmento de código que declara un receptor, podemos usar una aplicación como sección INSTALLED_APPS en settings.py

INSTALLED_APPS = [ # ... ''django_fullclean'', # your apps here, ]

Antes de eso, puede necesitar instalar django-fullclean usando PyPI:

pip install django-fullclean


La forma más sencilla de llamar al método full_clean es simplemente anular el método de save en su model :

def save(self, *args, **kwargs): self.full_clean() return super(YourModel, self).save(*args, **kwargs)


Si tiene un modelo que quiere asegurarse de que tiene al menos una relación FK, y no quiere usar null=False porque eso requiere establecer un FK predeterminado (que sería basura), la mejor forma en que he venido hasta con es agregar .clean() personalizados .clean() y .save() . .clean() aumenta el error de validación y .save() llama a la limpieza. De esta forma, la integridad se aplica tanto desde formularios como desde otro código de llamada, línea de comando y pruebas. Sin esto, no existe (AFAICT) ninguna forma de escribir una prueba que asegure que un modelo tenga una relación FK con un otro modelo específicamente elegido (no predeterminado).

class Payer(models.Model): name = models.CharField(blank=True, max_length=100) # Nullable, but will enforce FK in clean/save: payer_group = models.ForeignKey(PayerGroup, null=True, blank=True,) def clean(self): # Ensure every Payer is in a PayerGroup (but only via forms) if not self.payer_group: raise ValidationError( {''payer_group'': ''Each Payer must belong to a PayerGroup.''}) def save(self, *args, **kwargs): self.full_clean() return super().save(*args, **kwargs) def __str__(self): return self.name