From a717d74f3cc6c9526346c89f6828ceec493f725b Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:19:12 +0500 Subject: [PATCH 01/19] fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer --- rest_framework/serializers.py | 10 +++++- tests/test_serializer.py | 63 +++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+), 1 deletion(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 01bebf5fca..fb2a5bd1eb 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -589,6 +589,11 @@ def __init__(self, *args, **kwargs): self.min_length = kwargs.pop('min_length', None) assert self.child is not None, '`child` is a required argument.' assert not inspect.isclass(self.child), '`child` has not been instantiated.' + + if kwargs.get('instance', []) and kwargs.get('data', []): + assert len(kwargs.get("data", [])) == len( + kwargs.get("instance", [])), 'Data and instance should have same length' + super().__init__(*args, **kwargs) self.child.bind(field_name='', parent=self) @@ -663,7 +668,10 @@ def to_internal_value(self, data): ret = [] 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: validated = self.child.run_validation(item) except ValidationError as exc: diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 1d9efaa434..0f57ba6d28 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -762,3 +762,66 @@ class TestSerializer(serializers.Serializer): assert (s.data | {}).__class__ == s.data.__class__ assert ({} | s.data).__class__ == s.data.__class__ + + +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 + + +import unittest + + +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): + serializer = MyClassSerializer( + data=[{'value': 'set', 'id': instance.id} for instance in + self.objs], + instance=self.objs[:-1], + many=True, + partial=True, + ) \ No newline at end of file From 4bbc689ec5b442b2424086b21d1aed352bc96e8b Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:33:19 +0500 Subject: [PATCH 02/19] fix formatting issues for list serializer validation fix --- rest_framework/serializers.py | 2 +- tests/test_serializer.py | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index fb2a5bd1eb..9301484dc2 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -592,7 +592,7 @@ def __init__(self, *args, **kwargs): if kwargs.get('instance', []) and kwargs.get('data', []): assert len(kwargs.get("data", [])) == len( - kwargs.get("instance", [])), 'Data and instance should have same length' + kwargs.get("instance", [])), 'Data and instance should have same length' super().__init__(*args, **kwargs) self.child.bind(field_name='', parent=self) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 0f57ba6d28..cfa2e838cc 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -2,6 +2,7 @@ import pickle import re import sys +import unittest from collections import ChainMap from collections.abc import Mapping @@ -10,7 +11,6 @@ from rest_framework import exceptions, fields, relations, serializers from rest_framework.fields import Field - from .models import ( ForeignKeyTarget, NestedForeignKeySource, NullableForeignKeySource ) @@ -787,9 +787,6 @@ def validate_value(self, value): return value -import unittest - - class TestMultipleObjectsValidation(unittest.TestCase): def setUp(self): self.objs = [ @@ -818,10 +815,10 @@ def test_multiple_objects_are_validated_separately(self): def test_exception_raised_when_data_and_instance_length_different(self): with self.assertRaises(AssertionError): - serializer = MyClassSerializer( + MyClassSerializer( data=[{'value': 'set', 'id': instance.id} for instance in self.objs], instance=self.objs[:-1], many=True, partial=True, - ) \ No newline at end of file + ) From 516ba527dd181035049c9b7ecef9bd618da07376 Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:36:00 +0500 Subject: [PATCH 03/19] fix imports sorting for list serializer tests --- tests/test_serializer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index cfa2e838cc..9e286babd5 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -11,6 +11,7 @@ from rest_framework import exceptions, fields, relations, serializers from rest_framework.fields import Field + from .models import ( ForeignKeyTarget, NestedForeignKeySource, NullableForeignKeySource ) From b9c8d1923d0f017bd6b59efff5a9b3619067dd76 Mon Sep 17 00:00:00 2001 From: Mathieu Dupuy Date: Sun, 14 May 2023 02:00:13 +0200 Subject: [PATCH 04/19] remove django 2.2 from docs index (#8982) --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index cab5511ac1..ad241c0a37 100644 --- a/docs/index.md +++ b/docs/index.md @@ -86,7 +86,7 @@ continued development by **[signing up for a paid plan][funding]**. REST framework requires the following: * Python (3.6, 3.7, 3.8, 3.9, 3.10, 3.11) -* Django (2.2, 3.0, 3.1, 3.2, 4.0, 4.1) +* Django (3.0, 3.1, 3.2, 4.0, 4.1) We **highly recommend** and only officially support the latest patch release of each Python and Django series. From e6655e3b97ed7d1849a8a6077cf575cdc1d6efef Mon Sep 17 00:00:00 2001 From: Mehraz Hossain Rumman <59512321+MehrazRumman@users.noreply.github.com> Date: Mon, 15 May 2023 21:02:17 +0600 Subject: [PATCH 05/19] Declared Django 4.2 support in README.md (#8985) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e8375291dc..c2975a418f 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ There is a live example API for testing purposes, [available here][sandbox]. # Requirements * Python 3.6+ -* Django 4.1, 4.0, 3.2, 3.1, 3.0 +* Django 4.2, 4.1, 4.0, 3.2, 3.1, 3.0 We **highly recommend** and only officially support the latest patch release of each Python and Django series. From 01b99ddb9e5f1dd31c980bf57937dc3d689b3cdf Mon Sep 17 00:00:00 2001 From: Dominik Bruhn Date: Wed, 17 May 2023 07:46:48 +0200 Subject: [PATCH 06/19] 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 --- docs/api-guide/reverse.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api-guide/reverse.md b/docs/api-guide/reverse.md index 82dd168818..c3fa52f21f 100644 --- a/docs/api-guide/reverse.md +++ b/docs/api-guide/reverse.md @@ -54,5 +54,5 @@ As with the `reverse` function, you should **include the request as a keyword ar api_root = reverse_lazy('api-root', request=request) [cite]: https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm#sec_5_1_5 -[reverse]: https://docs.djangoproject.com/en/stable/topics/http/urls/#reverse -[reverse-lazy]: https://docs.djangoproject.com/en/stable/topics/http/urls/#reverse-lazy +[reverse]: https://docs.djangoproject.com/en/stable/ref/urlresolvers/#reverse +[reverse-lazy]: https://docs.djangoproject.com/en/stable/ref/urlresolvers/#reverse-lazy From 8d7e250046781a32635ed217e07afedfb00ddcb8 Mon Sep 17 00:00:00 2001 From: jornvanwier Date: Thu, 18 May 2023 05:46:40 +0200 Subject: [PATCH 07/19] 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 Co-authored-by: Asif Saif Uddin --- rest_framework/versioning.py | 6 ++++-- tests/test_versioning.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/rest_framework/versioning.py b/rest_framework/versioning.py index 78cfc9dc81..c2764c7a40 100644 --- a/rest_framework/versioning.py +++ b/rest_framework/versioning.py @@ -81,8 +81,10 @@ def determine_version(self, request, *args, **kwargs): def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra): if request.version is not None: - kwargs = {} if (kwargs is None) else kwargs - kwargs[self.version_param] = request.version + kwargs = { + self.version_param: request.version, + **(kwargs or {}) + } return super().reverse( viewname, args, kwargs, request, format, **extra diff --git a/tests/test_versioning.py b/tests/test_versioning.py index 93f61d2be4..b216461840 100644 --- a/tests/test_versioning.py +++ b/tests/test_versioning.py @@ -152,6 +152,8 @@ class TestURLReversing(URLPatternsTestCase, APITestCase): path('v1/', include((included, 'v1'), namespace='v1')), path('another/', dummy_view, name='another'), re_path(r'^(?P[v1|v2]+)/another/$', dummy_view, name='another'), + re_path(r'^(?P.+)/unversioned/$', dummy_view, name='unversioned'), + ] def test_reverse_unversioned(self): @@ -198,6 +200,14 @@ def test_reverse_url_path_versioning(self): response = view(request) assert response.data == {'url': 'http://testserver/another/'} + # Test fallback when kwargs is not None + request = factory.get('/v1/endpoint/') + request.versioning_scheme = scheme() + request.version = 'v1' + + reversed_url = reverse('unversioned', request=request, kwargs={'foo': 'bar'}) + assert reversed_url == 'http://testserver/bar/unversioned/' + def test_reverse_namespace_versioning(self): class FakeResolverMatch(ResolverMatch): namespace = 'v1' From b9b50bd0cc8b47797ccce9ad71199424993b7110 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Beaul=C3=A9?= Date: Wed, 24 May 2023 10:59:42 -0300 Subject: [PATCH 08/19] 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. --- rest_framework/fields.py | 21 --------------------- rest_framework/serializers.py | 24 ++++++++++++++++++++++-- tests/test_serializer.py | 21 +++++++++++++++++++++ 3 files changed, 43 insertions(+), 23 deletions(-) diff --git a/rest_framework/fields.py b/rest_framework/fields.py index 4f82e4a10e..623e72e0ad 100644 --- a/rest_framework/fields.py +++ b/rest_framework/fields.py @@ -113,27 +113,6 @@ def get_attribute(instance, attrs): return instance -def set_value(dictionary, keys, value): - """ - Similar to Python's built in `dictionary[key] = value`, - but takes a list of nested keys instead of a single key. - - set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2} - set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2} - set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}} - """ - if not keys: - dictionary.update(value) - return - - for key in keys[:-1]: - if key not in dictionary: - dictionary[key] = {} - dictionary = dictionary[key] - - dictionary[keys[-1]] = value - - def to_choices_dict(choices): """ Convert choices into key/value dicts. diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 9301484dc2..12723c9dcd 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -28,7 +28,7 @@ from rest_framework.compat import postgres_fields from rest_framework.exceptions import ErrorDetail, ValidationError -from rest_framework.fields import get_error_detail, set_value +from rest_framework.fields import get_error_detail from rest_framework.settings import api_settings from rest_framework.utils import html, model_meta, representation from rest_framework.utils.field_mapping import ( @@ -346,6 +346,26 @@ class Serializer(BaseSerializer, metaclass=SerializerMetaclass): 'invalid': _('Invalid data. Expected a dictionary, but got {datatype}.') } + def set_value(self, dictionary, keys, value): + """ + Similar to Python's built in `dictionary[key] = value`, + but takes a list of nested keys instead of a single key. + + set_value({'a': 1}, [], {'b': 2}) -> {'a': 1, 'b': 2} + set_value({'a': 1}, ['x'], 2) -> {'a': 1, 'x': 2} + set_value({'a': 1}, ['x', 'y'], 2) -> {'a': 1, 'x': {'y': 2}} + """ + if not keys: + dictionary.update(value) + return + + for key in keys[:-1]: + if key not in dictionary: + dictionary[key] = {} + dictionary = dictionary[key] + + dictionary[keys[-1]] = value + @cached_property def fields(self): """ @@ -492,7 +512,7 @@ def to_internal_value(self, data): except SkipField: pass else: - set_value(ret, field.source_attrs, validated_value) + self.set_value(ret, field.source_attrs, validated_value) if errors: raise ValidationError(errors) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 9e286babd5..39d9238ef9 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -765,6 +765,27 @@ class TestSerializer(serializers.Serializer): assert ({} | s.data).__class__ == s.data.__class__ +class TestSetValueMethod: + # Serializer.set_value() modifies the first parameter in-place. + + s = serializers.Serializer() + + def test_no_keys(self): + ret = {'a': 1} + self.s.set_value(ret, [], {'b': 2}) + assert ret == {'a': 1, 'b': 2} + + def test_one_key(self): + ret = {'a': 1} + self.s.set_value(ret, ['x'], 2) + assert ret == {'a': 1, 'x': 2} + + def test_nested_key(self): + ret = {'a': 1} + self.s.set_value(ret, ['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) From 869d46fc4294f5a30bdac1b0ffe2ef5e2c7fe21e Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:19:12 +0500 Subject: [PATCH 09/19] fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer --- tests/test_serializer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 39d9238ef9..9979c8e20b 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -837,10 +837,10 @@ def test_multiple_objects_are_validated_separately(self): def test_exception_raised_when_data_and_instance_length_different(self): with self.assertRaises(AssertionError): - MyClassSerializer( + serializer = MyClassSerializer( data=[{'value': 'set', 'id': instance.id} for instance in self.objs], instance=self.objs[:-1], many=True, partial=True, - ) + ) \ No newline at end of file From f969143c950e79ea6c71412b259118a888f1e1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89tienne=20Beaul=C3=A9?= Date: Wed, 24 May 2023 10:59:42 -0300 Subject: [PATCH 10/19] 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. --- tests/test_serializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 9979c8e20b..3d52f3c0a7 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -843,4 +843,4 @@ def test_exception_raised_when_data_and_instance_length_different(self): instance=self.objs[:-1], many=True, partial=True, - ) \ No newline at end of file + ) From a1f03d5ee673113d5c03ed03bcd67523bc376fc0 Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:19:12 +0500 Subject: [PATCH 11/19] fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer --- rest_framework/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 12723c9dcd..4c1866bfc2 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -612,7 +612,7 @@ def __init__(self, *args, **kwargs): if kwargs.get('instance', []) and kwargs.get('data', []): assert len(kwargs.get("data", [])) == len( - kwargs.get("instance", [])), 'Data and instance should have same length' + kwargs.get("instance", [])), 'Data and instance should have same length' super().__init__(*args, **kwargs) self.child.bind(field_name='', parent=self) From 9ac6417aade0b3f54c5ee1be0a561f413bc26482 Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:19:12 +0500 Subject: [PATCH 12/19] fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer --- tests/test_serializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 3d52f3c0a7..9979c8e20b 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -843,4 +843,4 @@ def test_exception_raised_when_data_and_instance_length_different(self): instance=self.objs[:-1], many=True, partial=True, - ) + ) \ No newline at end of file From 76110bf8a5c3a0e91be3bd7f9cefa6ea36060467 Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:33:19 +0500 Subject: [PATCH 13/19] fix formatting issues for list serializer validation fix --- rest_framework/serializers.py | 2 +- tests/test_serializer.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 4c1866bfc2..12723c9dcd 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -612,7 +612,7 @@ def __init__(self, *args, **kwargs): if kwargs.get('instance', []) and kwargs.get('data', []): assert len(kwargs.get("data", [])) == len( - kwargs.get("instance", [])), 'Data and instance should have same length' + kwargs.get("instance", [])), 'Data and instance should have same length' super().__init__(*args, **kwargs) self.child.bind(field_name='', parent=self) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 9979c8e20b..b82a796369 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -11,7 +11,6 @@ from rest_framework import exceptions, fields, relations, serializers from rest_framework.fields import Field - from .models import ( ForeignKeyTarget, NestedForeignKeySource, NullableForeignKeySource ) @@ -837,10 +836,10 @@ def test_multiple_objects_are_validated_separately(self): def test_exception_raised_when_data_and_instance_length_different(self): with self.assertRaises(AssertionError): - serializer = MyClassSerializer( + MyClassSerializer( data=[{'value': 'set', 'id': instance.id} for instance in self.objs], instance=self.objs[:-1], many=True, partial=True, - ) \ No newline at end of file + ) From c1ee7e75b1bf894311df0cce40ee0dd5e9ef141e Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:19:12 +0500 Subject: [PATCH 14/19] fix: Make the instance variable of child serializer point to the correct list object instead of the entire list when validating ListSerializer --- tests/test_serializer.py | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index b82a796369..52a154dc51 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -3,6 +3,7 @@ import re import sys import unittest + from collections import ChainMap from collections.abc import Mapping @@ -11,6 +12,7 @@ from rest_framework import exceptions, fields, relations, serializers from rest_framework.fields import Field + from .models import ( ForeignKeyTarget, NestedForeignKeySource, NullableForeignKeySource ) @@ -843,3 +845,63 @@ def test_exception_raised_when_data_and_instance_length_different(self): many=True, partial=True, ) + + +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): + serializer = MyClassSerializer( + data=[{'value': 'set', 'id': instance.id} for instance in + self.objs], + instance=self.objs[:-1], + many=True, + partial=True, + ) \ No newline at end of file From 74cb5002f58e5a424d3b4a9f61b446e59988f184 Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Thu, 11 May 2023 01:33:19 +0500 Subject: [PATCH 15/19] fix formatting issues for list serializer validation fix --- tests/test_serializer.py | 61 ---------------------------------------- 1 file changed, 61 deletions(-) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index 52a154dc51..f89dd08719 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -3,7 +3,6 @@ import re import sys import unittest - from collections import ChainMap from collections.abc import Mapping @@ -844,64 +843,4 @@ def test_exception_raised_when_data_and_instance_length_different(self): instance=self.objs[:-1], many=True, partial=True, - ) - - -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): - serializer = MyClassSerializer( - data=[{'value': 'set', 'id': instance.id} for instance in - self.objs], - instance=self.objs[:-1], - many=True, - partial=True, ) \ No newline at end of file From 7197a86428e2c95895dcf9e0f522885d806e34a2 Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Sat, 27 May 2023 16:39:26 +0500 Subject: [PATCH 16/19] fix linting --- tests/test_serializer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_serializer.py b/tests/test_serializer.py index f89dd08719..39d9238ef9 100644 --- a/tests/test_serializer.py +++ b/tests/test_serializer.py @@ -843,4 +843,4 @@ def test_exception_raised_when_data_and_instance_length_different(self): instance=self.objs[:-1], many=True, partial=True, - ) \ No newline at end of file + ) From bb4102a162bcfe49492ac47c42daf42933c00343 Mon Sep 17 00:00:00 2001 From: Asif Saif Uddin Date: Sat, 27 May 2023 18:17:51 +0600 Subject: [PATCH 17/19] Update rest_framework/serializers.py Co-authored-by: Sergei Shishov --- rest_framework/serializers.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 12723c9dcd..237dbbc705 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -689,8 +689,11 @@ def to_internal_value(self, data): errors = [] for idx, item in enumerate(data): - if hasattr(self, 'instance') and self.instance and \ - len(self.instance) > idx: + if ( + hasattr(self, 'instance') + and self.instance + and len(self.instance) > idx + ): self.child.instance = self.instance[idx] try: validated = self.child.run_validation(item) From 0dc62010b17c79d5b4c0aafdab525af28d71d379 Mon Sep 17 00:00:00 2001 From: Saad Aleem Date: Sat, 27 May 2023 21:27:25 +0500 Subject: [PATCH 18/19] Update rest_framework/serializers.py Co-authored-by: Sergei Shishov --- rest_framework/serializers.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 237dbbc705..9db5136479 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -610,9 +610,11 @@ def __init__(self, *args, **kwargs): assert self.child is not None, '`child` is a required argument.' assert not inspect.isclass(self.child), '`child` has not been instantiated.' - if kwargs.get('instance', []) and kwargs.get('data', []): - assert len(kwargs.get("data", [])) == len( - kwargs.get("instance", [])), 'Data and instance should have same length' + # instance, data = kwargs.get('instance', []), kwargs.get('data', []) # if you prefer one line assignment support + 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) self.child.bind(field_name='', parent=self) From d74744969546bcd4a57223abb3d5f7dd8badec50 Mon Sep 17 00:00:00 2001 From: Saadullah Aleem Date: Sun, 28 May 2023 22:57:51 +0500 Subject: [PATCH 19/19] fix: instance variable in list serializer, remove commented code --- rest_framework/serializers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/rest_framework/serializers.py b/rest_framework/serializers.py index 9db5136479..56fa918dc8 100644 --- a/rest_framework/serializers.py +++ b/rest_framework/serializers.py @@ -610,7 +610,6 @@ def __init__(self, *args, **kwargs): assert self.child is not None, '`child` is a required argument.' assert not inspect.isclass(self.child), '`child` has not been instantiated.' - # instance, data = kwargs.get('instance', []), kwargs.get('data', []) # if you prefer one line assignment support instance = kwargs.get('instance', []) data = kwargs.get('data', []) if instance and data: pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy