Fix validation for ListSerializer (#8979)

* fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer

* fix formatting issues for list serializer validation fix

* fix imports sorting for list serializer tests

* remove django 2.2 from docs index (#8982)

* Declared Django 4.2 support in README.md (#8985)

* Fix Links in Documentation to Django `reverse` and `reverse_lazy` (#8986)

* Fix Django Docs url in reverse.md

Django URLs of the documentation of `reverse` and `reverse_lazy` were wrong.

* Update reverse.md

* fix URLPathVersioning reverse fallback (#7247)

* fix URLPathVersioning reverse fallback

* add test for URLPathVersioning reverse fallback

* Update tests/test_versioning.py

---------

Co-authored-by: Jorn van Wier <jorn.van.wier@thunderbyte.ai>
Co-authored-by: Asif Saif Uddin <auvipy@gmail.com>

* Make set_value a method within `Serializer` (#8001)

* Make set_value a static method for Serializers

As an alternative to #7671, let the method be overridden if needed. As
the function is only used for serializers, it has a better place in the
Serializer class.

* Set `set_value` as an object (non-static) method

* Add tests for set_value()

These tests follow the examples given in the method.

* fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer

* Make set_value a method within `Serializer` (#8001)

* Make set_value a static method for Serializers

As an alternative to #7671, let the method be overridden if needed. As
the function is only used for serializers, it has a better place in the
Serializer class.

* Set `set_value` as an object (non-static) method

* Add tests for set_value()

These tests follow the examples given in the method.

* fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer

* fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer

* fix formatting issues for list serializer validation fix

* fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer

* fix formatting issues for list serializer validation fix

* fix linting

* Update rest_framework/serializers.py

Co-authored-by: Sergei Shishov <sshishov@users.noreply.github.com>

* Update rest_framework/serializers.py

Co-authored-by: Sergei Shishov <sshishov@users.noreply.github.com>

* fix: instance variable in list serializer, remove commented code

---------

Co-authored-by: Mathieu Dupuy <deronnax@gmail.com>
Co-authored-by: Mehraz Hossain Rumman <59512321+MehrazRumman@users.noreply.github.com>
Co-authored-by: Dominik Bruhn <dominik@dbruhn.de>
Co-authored-by: jornvanwier <mail@jornvanwier.com>
Co-authored-by: Jorn van Wier <jorn.van.wier@thunderbyte.ai>
Co-authored-by: Asif Saif Uddin <auvipy@gmail.com>
Co-authored-by: Étienne Beaulé <beauleetienne0@gmail.com>
Co-authored-by: Sergei Shishov <sshishov@users.noreply.github.com>
This commit is contained in:
Saad Aleem 2023-05-29 19:03:11 +05:00 committed by GitHub
parent d252d22343
commit e2a4559c03
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 74 additions and 1 deletions

View File

@ -609,6 +609,12 @@ class ListSerializer(BaseSerializer):
self.min_length = kwargs.pop('min_length', None) self.min_length = kwargs.pop('min_length', None)
assert self.child is not None, '`child` is a required argument.' assert self.child is not None, '`child` is a required argument.'
assert not inspect.isclass(self.child), '`child` has not been instantiated.' assert not inspect.isclass(self.child), '`child` has not been instantiated.'
instance = kwargs.get('instance', [])
data = kwargs.get('data', [])
if instance and data:
assert len(data) == len(instance), 'Data and instance should have same length'
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.child.bind(field_name='', parent=self) self.child.bind(field_name='', parent=self)
@ -683,7 +689,13 @@ class ListSerializer(BaseSerializer):
ret = [] ret = []
errors = [] errors = []
for item in data: for idx, item in enumerate(data):
if (
hasattr(self, 'instance')
and self.instance
and len(self.instance) > idx
):
self.child.instance = self.instance[idx]
try: try:
validated = self.child.run_validation(item) validated = self.child.run_validation(item)
except ValidationError as exc: except ValidationError as exc:

View File

@ -2,6 +2,7 @@ import inspect
import pickle import pickle
import re import re
import sys import sys
import unittest
from collections import ChainMap from collections import ChainMap
from collections.abc import Mapping from collections.abc import Mapping
@ -783,3 +784,63 @@ class TestSetValueMethod:
ret = {'a': 1} ret = {'a': 1}
self.s.set_value(ret, ['x', 'y'], 2) self.s.set_value(ret, ['x', 'y'], 2)
assert ret == {'a': 1, 'x': {'y': 2}} assert ret == {'a': 1, 'x': {'y': 2}}
class MyClass(models.Model):
name = models.CharField(max_length=100)
value = models.CharField(max_length=100, blank=True)
app_label = "test"
@property
def is_valid(self):
return self.name == 'valid'
class MyClassSerializer(serializers.ModelSerializer):
class Meta:
model = MyClass
fields = ('id', 'name', 'value')
def validate_value(self, value):
if value and not self.instance.is_valid:
raise serializers.ValidationError(
'Status cannot be set for invalid instance')
return value
class TestMultipleObjectsValidation(unittest.TestCase):
def setUp(self):
self.objs = [
MyClass(name='valid'),
MyClass(name='invalid'),
MyClass(name='other'),
]
def test_multiple_objects_are_validated_separately(self):
serializer = MyClassSerializer(
data=[{'value': 'set', 'id': instance.id} for instance in
self.objs],
instance=self.objs,
many=True,
partial=True,
)
assert not serializer.is_valid()
assert serializer.errors == [
{},
{'value': ['Status cannot be set for invalid instance']},
{'value': ['Status cannot be set for invalid instance']}
]
def test_exception_raised_when_data_and_instance_length_different(self):
with self.assertRaises(AssertionError):
MyClassSerializer(
data=[{'value': 'set', 'id': instance.id} for instance in
self.objs],
instance=self.objs[:-1],
many=True,
partial=True,
)