How to validate a field on update in DRF

+1 vote

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):
            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 != int(validated_data['spouse']):
            raise ValidationError('Till death do us part!') = validation_data.get('name',
        return person

   # the way I want to do this
   def validate_spouse(self, value):
       # do validation magic
Jul 1, 2020 in Python by kartik
• 37,490 points

1 answer to this question.

0 votes

Hello @kartik,

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. 

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

 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

Hope it helps!!
Thank You!!

answered Jul 1, 2020 by Niroj
• 82,560 points

Related Questions In Python

0 votes
1 answer

List comprehension on a nested list - How to do it in Python?

Not sure what your desired output is, ...READ MORE

answered Nov 21, 2018 in Python by Nymeria
• 3,520 points
0 votes
1 answer

Question on PyQt: How to connect a signal to a slot to start a background operation in Python

It shouldn't matter whether the connection is ...READ MORE

answered Nov 27, 2018 in Python by Nymeria
• 3,520 points
0 votes
1 answer

I have a dictonary in python how to access the value field?

dic={"car":["limo","sedan"]} print (dic.keys())    <-----------------------Fetch the key "car" print (dic['car'][0])   <------------------------Fetch ...READ MORE

answered Dec 19, 2018 in Python by Shuvodip
0 votes
1 answer

How to temporarily disable a foreign key constraint in MySQL?

Hello @kartik, To turn off foreign key constraint ...READ MORE

answered Jun 23, 2020 in Python by Niroj
• 82,560 points
0 votes
1 answer

How do I use Django templates without the rest of Django?

Hello @kartik, Let's say you have this important ...READ MORE

answered Jun 23, 2020 in Python by Niroj
• 82,560 points
0 votes
1 answer

How to update date automatically after a value change in django?

Hello @kartik, Only change your pub_date if published has ...READ MORE

answered Jul 2, 2020 in Python by Niroj
• 82,560 points
+1 vote
3 answers

How to change/update cell value in Python Pandas dataframe?

You can use the at() method to ...READ MORE

answered Apr 8, 2019 in Python by Kunal