Как проверить поле при обновлении в DRF?

у меня есть сериализатор для модели с внешним ключом. Требование состоит в том, что при создании внешний ключ может быть установлен на любой существующий объект из связанной модели, но при обновлении Связанный объект не может быть изменен. Я могу проверить это в пользовательском update(), но было бы более элегантно использовать проверку сериализатора для проверки этого? Но я не знаю как. Пример кода:

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

1 ответов


вы можете определенно сделать это, используя проверку на поле. То, как вы проверяете, является ли это обновлением или созданием, проверяет self.instance в функции проверки. Там немного упоминается об этом в документации сериализатор.

self.instance будет содержать существующий объект и его значения, поэтому вы можете использовать его для сравнения.

Я считаю, что это должно работать для ваших целей:

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

другой способ сделать это переопределить, если поле read_only, если вы обновляете. Это можно сделать в __init__ сериализатора. Подобно валидатору, вы просто ищете экземпляр, и если есть данные:

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