mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-25 11:04:02 +03:00
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:
parent
d252d22343
commit
e2a4559c03
|
@ -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:
|
||||||
|
|
|
@ -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,
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user