Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to validate a field on update in DRF?

Tags:

I have a serializer for a model with a foreign key. The requirement is that on create, foreign key can be set to any existing object from the related model, but on update the related object cannot be changed. I can check this in the custom update(), but it would be more elegant to use serializer validation to check for this? But I am not sure how. Example code:

class Person(models.Model):     name = models.CharField(max_length=256)     spouse = models.ForeignKey(Person)  class PersonSerializer(serializers.ModelSerializer):     class Meta:         model = Person      # this is how I know how to do this     def create(self, validated_data):         try:             spouse = Person.objects.get(pk=int(validated_data.pop('spouse')))         except Person.DoesNotExist:             raise ValidationError('Imaginary spouses not allowed!')         return Person.objects.create(spouse=spouse, **validation_data)      def update(self, person, validated_data):         if person.spouse.pk != int(validated_data['spouse']):             raise ValidationError('Till death do us part!')         person.name = validation_data.get('name', person.name)         person.save()         return person     # the way I want to do this    def validate_spouse(self, value):        # do validation magic 
like image 965
Mad Wombat Avatar asked Sep 20 '16 15:09

Mad Wombat


People also ask

How does Django validate data in serializer?

Validation in Django REST framework serializers is handled a little differently to how validation works in Django's ModelForm class. With ModelForm the validation is performed partially on the form, and partially on the model instance. With REST framework the validation is performed entirely on the serializer class.

How does Django validate data?

Django forms submit only if it contains CSRF tokens. It uses uses a clean and easy approach to validate data. The is_valid() method is used to perform validation for each field of the form, it is defined in Django Form class. It returns True if data is valid and place all data into a cleaned_data attribute.


1 Answers

You can definitely do this using the validation on a field. The way you'd check if it's an update vs. creation is checking for self.instance in the validation function. There's a bit mentioned about it in the serializer documentation.

self.instance will hold the existing object and it's values, so you can then use it to compare against.

I believe this should work for your purposes:

def validate_spouse(self, value):     if self.instance and value != self.instance.spouse:         raise serializers.ValidationError("Till death do us part!")     return value 

Another way to do this is to override if the field is read_only if you're updating. This can be done in the __init__ of the serializer. Similar to the validator, you'd simply look for an instance and if there's data:

def __init__(self, *args, **kwargs):     # Check if we're updating.     updating = "instance" in kwargs and "data" in kwargs      # Make sure the original initialization is done first.     super().__init__(*args, **kwargs)      # If we're updating, make the spouse field read only.     if updating:         self.fields['spouse'].read_only = True 
like image 162
tredzko Avatar answered Sep 26 '22 19:09

tredzko