Django doesn't call model clean method
Question:
I have a view, which creates models from CSV file. I’ve added clean method to the model class definition, but it isn’t called when model is created.
Here is example of models.py:
class Run(models.Model):
name = models.CharField(max_length=120)
tested_build = models.ForeignKey('apps.Build')
timestamp_start = models.DateTimeField()
timestamp_end = models.DateTimeField()
class CommonMeasurement(models.Model):
timestamp = models.DateTimeField()
value = models.FloatField()
run = models.ForeignKey(Run)
def clean(self):
super(CommonMeasurement, self).clean()
print 'here we go'
if self.timestamp < self.run.timestamp_start or self.timestamp > self.run.timestamp_end:
raise django_excetions.ValidationError('Measurement is outside the run')
class ClientMeasurement(CommonMeasurement):
metric = models.ForeignKey(ClientMetric)
account = models.CharField(max_length=120, blank=True)
Here is my Form View code examples:
class BaseMeasurementsUpload(generic_views.FormView):
template_name = 'upload.html'
models_to_upload = None
def get_success_url(self):
return self.request.get_full_path()
def form_valid(self, form):
uploader = getattr(importers, form.cleaned_data['uploader'])
try:
the_uploader = uploader(form.cleaned_data, self.models_to_upload)
upload_results = the_uploader.get_result_info()
except django_exceptions.ValidationError as e:
custom_errors = e
return render_to_response(self.template_name,
{'upload_results': upload_results,
'custom_errors': custom_errors},
context_instance=RequestContext(self.request))
class ClientMeasurementsUploadView(BaseMeasurementsUpload):
form_class = forms.ClientMeasurementsUploadForm
models_to_upload = models.ClientMeasurement
def get_form(self, form_class):
uploaders = (('MeasurementsSimpleCsv', importers.MeasurementsSimpleCsv.__doc__),
('ClientMeasurementsBulkCsv', importers.ClientMeasurementsBulkCsv.__doc__,))
if self.request.POST:
# get bound form
return self.form_class(uploaders,
self.request.POST,
self.request.FILES)
else:
return forms.ClientMeasurementsUploadForm(uploaders)
importers perform actual validation and call create method for each model.
Answers:
I’ve found a solution to override method:
class CommonMeasurement(models.Model):
timestamp = models.DateTimeField()
value = models.FloatField()
run = models.ForeignKey(Run)
objects = models.Manager()
analyzes = managers.MeasureStatManager()
def save(self, **kwargs):
self.clean()
return super(CommonMeasurement, self).save(**kwargs)
def clean(self):
super(CommonMeasurement, self).clean()
print 'here we go'
if self.timestamp < self.run.timestamp_start or self.timestamp > self.run.timestamp_end:
raise django_excetions.ValidationError('Measurement is outside the run')
But I’m not sure that it can be a good decision.
Apparently model.clean() is never called to ensure backward compatibility. For more information on this: https://code.djangoproject.com/ticket/13100
To call the model clean method we will override save method. Check the link: https://docs.djangoproject.com/en/2.0/ref/models/instances/#django.db.models.Model.clean
class CommonMeasurement(models.Model):
timestamp = models.DateTimeField()
value = models.FloatField()
run = models.ForeignKey(Run)
def clean(self):
if self.timestamp < self.run.timestamp_start or self.timestamp > self.run.timestamp_end:
raise django_excetions.ValidationError('Measurement is outside the run')
def save(self, *args, **kwargs):
self.full_clean()
return super(CommonMeasurement, self).save(*args, **kwargs)
Apparently in newer versions of Django the ModelForm.full_clean
does call it’s instance’s full_clean
method:
I have a view, which creates models from CSV file. I’ve added clean method to the model class definition, but it isn’t called when model is created.
Here is example of models.py:
class Run(models.Model):
name = models.CharField(max_length=120)
tested_build = models.ForeignKey('apps.Build')
timestamp_start = models.DateTimeField()
timestamp_end = models.DateTimeField()
class CommonMeasurement(models.Model):
timestamp = models.DateTimeField()
value = models.FloatField()
run = models.ForeignKey(Run)
def clean(self):
super(CommonMeasurement, self).clean()
print 'here we go'
if self.timestamp < self.run.timestamp_start or self.timestamp > self.run.timestamp_end:
raise django_excetions.ValidationError('Measurement is outside the run')
class ClientMeasurement(CommonMeasurement):
metric = models.ForeignKey(ClientMetric)
account = models.CharField(max_length=120, blank=True)
Here is my Form View code examples:
class BaseMeasurementsUpload(generic_views.FormView):
template_name = 'upload.html'
models_to_upload = None
def get_success_url(self):
return self.request.get_full_path()
def form_valid(self, form):
uploader = getattr(importers, form.cleaned_data['uploader'])
try:
the_uploader = uploader(form.cleaned_data, self.models_to_upload)
upload_results = the_uploader.get_result_info()
except django_exceptions.ValidationError as e:
custom_errors = e
return render_to_response(self.template_name,
{'upload_results': upload_results,
'custom_errors': custom_errors},
context_instance=RequestContext(self.request))
class ClientMeasurementsUploadView(BaseMeasurementsUpload):
form_class = forms.ClientMeasurementsUploadForm
models_to_upload = models.ClientMeasurement
def get_form(self, form_class):
uploaders = (('MeasurementsSimpleCsv', importers.MeasurementsSimpleCsv.__doc__),
('ClientMeasurementsBulkCsv', importers.ClientMeasurementsBulkCsv.__doc__,))
if self.request.POST:
# get bound form
return self.form_class(uploaders,
self.request.POST,
self.request.FILES)
else:
return forms.ClientMeasurementsUploadForm(uploaders)
importers perform actual validation and call create method for each model.
I’ve found a solution to override method:
class CommonMeasurement(models.Model):
timestamp = models.DateTimeField()
value = models.FloatField()
run = models.ForeignKey(Run)
objects = models.Manager()
analyzes = managers.MeasureStatManager()
def save(self, **kwargs):
self.clean()
return super(CommonMeasurement, self).save(**kwargs)
def clean(self):
super(CommonMeasurement, self).clean()
print 'here we go'
if self.timestamp < self.run.timestamp_start or self.timestamp > self.run.timestamp_end:
raise django_excetions.ValidationError('Measurement is outside the run')
But I’m not sure that it can be a good decision.
Apparently model.clean() is never called to ensure backward compatibility. For more information on this: https://code.djangoproject.com/ticket/13100
To call the model clean method we will override save method. Check the link: https://docs.djangoproject.com/en/2.0/ref/models/instances/#django.db.models.Model.clean
class CommonMeasurement(models.Model):
timestamp = models.DateTimeField()
value = models.FloatField()
run = models.ForeignKey(Run)
def clean(self):
if self.timestamp < self.run.timestamp_start or self.timestamp > self.run.timestamp_end:
raise django_excetions.ValidationError('Measurement is outside the run')
def save(self, *args, **kwargs):
self.full_clean()
return super(CommonMeasurement, self).save(*args, **kwargs)
Apparently in newer versions of Django the ModelForm.full_clean
does call it’s instance’s full_clean
method: