mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-25 02:53:58 +03:00
Allow to override child.run_validation call in ListSerializer (#8035)
* Separated run_child_validation method in ListSerializer * fix typo * Add test_update_allow_custom_child_validation --------- Co-authored-by: Pierre Chiquet <pierre.chiquet@ubikey.fr>
This commit is contained in:
parent
b99df0cf78
commit
589b5dca9e
|
@ -653,6 +653,17 @@ class ListSerializer(BaseSerializer):
|
||||||
|
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
def run_child_validation(self, data):
|
||||||
|
"""
|
||||||
|
Run validation on child serializer.
|
||||||
|
You may need to override this method to support multiple updates. For example:
|
||||||
|
|
||||||
|
self.child.instance = self.instance.get(pk=data['id'])
|
||||||
|
self.child.initial_data = data
|
||||||
|
return super().run_child_validation(data)
|
||||||
|
"""
|
||||||
|
return self.child.run_validation(data)
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
"""
|
"""
|
||||||
List of dicts of native values <- List of dicts of primitive datatypes.
|
List of dicts of native values <- List of dicts of primitive datatypes.
|
||||||
|
@ -697,7 +708,7 @@ class ListSerializer(BaseSerializer):
|
||||||
):
|
):
|
||||||
self.child.instance = self.instance[idx]
|
self.child.instance = self.instance[idx]
|
||||||
try:
|
try:
|
||||||
validated = self.child.run_validation(item)
|
validated = self.run_child_validation(item)
|
||||||
except ValidationError as exc:
|
except ValidationError as exc:
|
||||||
errors.append(exc.detail)
|
errors.append(exc.detail)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -153,6 +153,61 @@ class TestListSerializerContainingNestedSerializer:
|
||||||
assert serializer.is_valid()
|
assert serializer.is_valid()
|
||||||
assert serializer.validated_data == expected_output
|
assert serializer.validated_data == expected_output
|
||||||
|
|
||||||
|
def test_update_allow_custom_child_validation(self):
|
||||||
|
"""
|
||||||
|
Update a list of objects thanks custom run_child_validation implementation.
|
||||||
|
"""
|
||||||
|
|
||||||
|
class TestUpdateSerializer(serializers.Serializer):
|
||||||
|
integer = serializers.IntegerField()
|
||||||
|
boolean = serializers.BooleanField()
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
instance._data.update(validated_data)
|
||||||
|
return instance
|
||||||
|
|
||||||
|
def validate(self, data):
|
||||||
|
# self.instance is set to current BasicObject instance
|
||||||
|
assert isinstance(self.instance, BasicObject)
|
||||||
|
# self.initial_data is current dictionary
|
||||||
|
assert isinstance(self.initial_data, dict)
|
||||||
|
assert self.initial_data["pk"] == self.instance.pk
|
||||||
|
return super().validate(data)
|
||||||
|
|
||||||
|
class ListUpdateSerializer(serializers.ListSerializer):
|
||||||
|
child = TestUpdateSerializer()
|
||||||
|
|
||||||
|
def run_child_validation(self, data):
|
||||||
|
# find related instance in self.instance list
|
||||||
|
child_instance = next(o for o in self.instance if o.pk == data["pk"])
|
||||||
|
# set instance and initial_data for child serializer
|
||||||
|
self.child.instance = child_instance
|
||||||
|
self.child.initial_data = data
|
||||||
|
return super().run_child_validation(data)
|
||||||
|
|
||||||
|
def update(self, instance, validated_data):
|
||||||
|
return [
|
||||||
|
self.child.update(instance, attrs)
|
||||||
|
for instance, attrs in zip(self.instance, validated_data)
|
||||||
|
]
|
||||||
|
|
||||||
|
instance = [
|
||||||
|
BasicObject(pk=1, integer=11, private_field="a"),
|
||||||
|
BasicObject(pk=2, integer=22, private_field="b"),
|
||||||
|
]
|
||||||
|
input_data = [
|
||||||
|
{"pk": 1, "integer": "123", "boolean": "true"},
|
||||||
|
{"pk": 2, "integer": "456", "boolean": "false"},
|
||||||
|
]
|
||||||
|
expected_output = [
|
||||||
|
BasicObject(pk=1, integer=123, boolean=True, private_field="a"),
|
||||||
|
BasicObject(pk=2, integer=456, boolean=False, private_field="b"),
|
||||||
|
]
|
||||||
|
serializer = ListUpdateSerializer(instance, data=input_data)
|
||||||
|
assert serializer.is_valid()
|
||||||
|
updated_instances = serializer.save()
|
||||||
|
assert updated_instances == expected_output
|
||||||
|
|
||||||
|
|
||||||
class TestNestedListSerializer:
|
class TestNestedListSerializer:
|
||||||
"""
|
"""
|
||||||
|
@ -481,7 +536,7 @@ class TestSerializerPartialUsage:
|
||||||
assert serializer.validated_data == {}
|
assert serializer.validated_data == {}
|
||||||
assert serializer.errors == {}
|
assert serializer.errors == {}
|
||||||
|
|
||||||
def test_udate_as_field_allow_empty_true(self):
|
def test_update_as_field_allow_empty_true(self):
|
||||||
class ListSerializer(serializers.Serializer):
|
class ListSerializer(serializers.Serializer):
|
||||||
update_field = serializers.IntegerField()
|
update_field = serializers.IntegerField()
|
||||||
store_field = serializers.IntegerField()
|
store_field = serializers.IntegerField()
|
||||||
|
|
Loading…
Reference in New Issue
Block a user