Reputation: 65
I am trying to figure out how to use validations when creating an object in django.
From my POV, there are 2 approaches:
validate_field
method of the DRF serializers..save()
method of the model.Both ways seem to have their cons.
By using approach 1 my models are left "unprotected" from any other .create()
call of the model besides the serializers. Approach 2 deals with the above issue, but makes the code more complex since exception handling is neccessary in serializer's .create()
method.
Is there anyone that has faced a similar issue and/or found a "cleaner" way to deal with this?
Upvotes: 0
Views: 2053
Reputation: 1261
As far as i understood you need Django model validation. You can try this approach (I think, this is exactly what you want).
from django.core.exceptions import ValidationError
class Foo(models.Model):
name = models.CharField(max_length=255)
def clean(self):
raise ValidationError('Problem during validation')
f = Foo(name='test')
f.full_clean() # This is what you need. f.clean() will be enough, but f.full_clean() will make field level validations (run validators) and checking about uniqueness also.
f.save()
In general Django never makes model level validations(Does not call full_clean()
), during model creation.
f = Foo(**fields_dict)
f.save() # no validation performed.
call it yourself if you want,,,
f = Foo(**fields_dict)
f.full_clean() # validation performed
f.save()
full_clean()
method is performed automatically, if you use ModelForm
class. This is additional hook by Django.
Upvotes: 2
Reputation: 5450
I think that moving the validations down to the model is the safest way to ensure the highest level of reliability, because the validations are going to be applied as long as they are done through Django (if you use serializers, validations wouldn't work if Django Rest Framework is skipped).
Model level validations can be:
Field level validations: You create a method that makes the validation, and set such method as field validator:
from django.core.exceptions import ValidationError
from django.utils.translation import gettext_lazy as _
def validate_even(value):
if value % 2 != 0:
raise ValidationError(
_('%(value)s is not an even number'),
params={'value': value},
)
from django.db import models
class MyModel(models.Model):
even_field = models.IntegerField(validators=[validate_even])
Model level validations: You override model's clean()
method and perform the required validations:
import datetime
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import gettext_lazy as _
class Article(models.Model):
...
def clean(self):
# 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.date.today()
Upvotes: 0