Skip to content

Commit 5502965

Browse files
committed
updated child validation for ListSerializer
1 parent 1472848 commit 5502965

File tree

3 files changed

+72
-1
lines changed

3 files changed

+72
-1
lines changed

rest_framework/serializers.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,6 +652,14 @@ def run_child_validation(self, data):
652652
self.child.initial_data = data
653653
return super().run_child_validation(data)
654654
"""
655+
instance = None
656+
if self.instance is not None:
657+
instance_map = {getattr(obj, 'pk', None): obj for obj in self.instance}
658+
obj_id = data.get('id') or data.get('pk')
659+
instance = instance_map.get(obj_id)
660+
661+
self.child.instance = instance
662+
self.child.initial_data = data
655663
return self.child.run_validation(data)
656664

657665
def to_internal_value(self, data):

tests/models.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,3 +150,12 @@ def __new__(cls, *args, **kwargs):
150150
help_text='OneToOneTarget',
151151
verbose_name='OneToOneTarget',
152152
on_delete=models.CASCADE)
153+
154+
155+
class TestListModel(models.Model):
156+
name = models.CharField(max_length=100)
157+
status = models.CharField(max_length=100, blank=True)
158+
159+
@property
160+
def is_valid(self):
161+
return self.name == 'valid'

tests/test_serializer_lists.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from rest_framework import serializers
66
from rest_framework.exceptions import ErrorDetail
77
from tests.models import (
8-
CustomManagerModel, NullableOneToOneSource, OneToOneTarget
8+
CustomManagerModel, NullableOneToOneSource, OneToOneTarget, TestListModel
99
)
1010

1111

@@ -775,3 +775,57 @@ def test(self):
775775
queryset = NullableOneToOneSource.objects.all()
776776
serializer = self.serializer(queryset, many=True)
777777
assert serializer.data
778+
779+
780+
class TestManyTrueValidationCheck:
781+
"""
782+
Tests ListSerializer validation with many=True for both valid and invalid model data.
783+
"""
784+
785+
@pytest.mark.django_db
786+
def test_run_child_validation_with_many_true(self):
787+
obj1 = TestListModel.objects.create(name="valid", status="new")
788+
obj2 = TestListModel.objects.create(name="invalid", status="")
789+
790+
class TestListModelSerializer(serializers.ModelSerializer):
791+
class Meta:
792+
model = TestListModel
793+
fields = ("id", "name", "status")
794+
795+
def validate_status(self, value):
796+
if value and not self.instance.is_valid:
797+
return False
798+
return value
799+
800+
input_data = [
801+
{"id": obj1.id, "name": "other", "status": "new"},
802+
{"id": obj2.id, "name": "valid", "status": "progress"},
803+
]
804+
805+
serializer = TestListModelSerializer([obj1, obj2], data=input_data, many=True)
806+
assert serializer.is_valid(), serializer.errors
807+
808+
serializer = TestListModelSerializer(TestListModel.objects.all(), data=input_data, many=True)
809+
assert serializer.is_valid(), serializer.errors
810+
811+
@pytest.mark.django_db
812+
def test_validation_error_for_invalid_data(self):
813+
obj = TestListModel.objects.create(name="valid", status="some-status")
814+
815+
class TestListModelSerializer(serializers.ModelSerializer):
816+
class Meta:
817+
model = TestListModel
818+
fields = ("id", "name", "status")
819+
820+
def validate_status(self, value):
821+
if value and not self.instance.is_valid:
822+
return False
823+
return value
824+
825+
input_data = [
826+
{"id": obj.pk, "name": "", "status": -1},
827+
]
828+
829+
serializer = TestListModelSerializer([obj], data=input_data, many=True)
830+
assert not serializer.is_valid()
831+
assert "name" in serializer.errors[0]

0 commit comments

Comments
 (0)