Solución:
El patrón básico que he encontrado útil es poner toda mi validación personalizada en clean()
y luego simplemente llama full_clean()
(que llama clean()
y algunos otros métodos) desde adentro save()
, p.ej:
class BaseModel(models.Model):
def clean(self, *args, **kwargs):
# add custom validation here
super(BaseModel, self).clean(*args, **kwargs)
def save(self, *args, **kwargs):
self.full_clean()
super(BaseModel, self).save(*args, **kwargs)
Esto no se hace de forma predeterminada, como se explica aquí, porque interfiere con ciertas funciones, pero esas no son un problema para mi aplicación.
Yo anularía el validate_unique
método en el modelo. Para asegurarse de ignorar el objeto actual al validar, puede utilizar lo siguiente:
from django.db.models import Model, DateTimeField
from django.core.validators import NON_FIELD_ERRORS, ValidationError
class MyModel(Model):
start_date = DateTimeField()
end_date = DateTimeField()
def validate_unique(self, *args, **kwargs):
super(MyModel, self).validate_unique(*args, **kwargs)
qs = self.__class__._default_manager.filter(
start_date__lt=self.end_date,
end_date__gt=self.start_date
)
if not self._state.adding and self.pk is not None:
qs = qs.exclude(pk=self.pk)
if qs.exists():
raise ValidationError({
NON_FIELD_ERRORS: ['overlapping date range',],
})
ModelForm
lo llamará automáticamente a través de un full_clean()
, que también puede utilizar manualmente.
PPR tiene una buena discusión sobre una condición de superposición de rango simple y correcta.
Creo que deberías usar esto: https://docs.djangoproject.com/en/dev/ref/models/instances/#validating-objects
Simplemente defina el método clean () en su modelo de esta manera: (ejemplo del enlace de documentos)
def clean(self):
from django.core.exceptions import ValidationError
# Don't allow draft entries to have a pub_date.
if self.status == 'draft' and self.pub_date is not None:
raise ValidationError('Draft entries may not have a publication date.')
# Set the pub_date for published items if it hasn't been set already.
if self.status == 'published' and self.pub_date is None:
self.pub_date = datetime.datetime.now()