mirror of
https://github.com/encode/django-rest-framework.git
synced 2026-01-09 18:20:55 +03:00
Prevent NestedBoundField child access crash after parent validation error (#4073)
This commit is contained in:
parent
055c422b34
commit
3fc1c73168
|
|
@ -130,13 +130,21 @@ class NestedBoundField(BoundField):
|
|||
def __getitem__(self, key):
|
||||
field = self.fields[key]
|
||||
value = self.value.get(key) if self.value else None
|
||||
error = self.errors.get(key) if isinstance(self.errors, dict) else None
|
||||
|
||||
if isinstance(self.errors, dict):
|
||||
error = self.errors.get(key)
|
||||
elif isinstance(self.errors, list):
|
||||
error = {} # normalize list to empty dict for nested children
|
||||
else:
|
||||
error = None
|
||||
|
||||
if hasattr(field, 'fields'):
|
||||
return NestedBoundField(field, value, error, prefix=self.name + '.')
|
||||
elif getattr(field, '_is_jsonfield', False):
|
||||
return JSONBoundField(field, value, error, prefix=self.name + '.')
|
||||
return BoundField(field, value, error, prefix=self.name + '.')
|
||||
|
||||
|
||||
def as_form_field(self):
|
||||
values = {}
|
||||
for key, value in self.value.items():
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
from django.http import QueryDict
|
||||
|
||||
from rest_framework import serializers
|
||||
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
class TestSimpleBoundField:
|
||||
def test_empty_bound_field(self):
|
||||
|
|
@ -211,6 +211,42 @@ class TestNestedBoundField:
|
|||
rendered_packed = ''.join(rendered.split())
|
||||
assert rendered_packed == expected_packed
|
||||
|
||||
def test_child_bound_field_after_parent_validation_error(self):
|
||||
"""
|
||||
After a parent-level ValidationError on a nested serializer field,
|
||||
child BoundFields should remain accessible and receive a mapping
|
||||
for `errors` so the Browsable API can render safely.
|
||||
|
||||
Regression test for #4073.
|
||||
"""
|
||||
class ChildSerializer(serializers.Serializer):
|
||||
value = serializers.CharField()
|
||||
class ParentSerializer(serializers.Serializer):
|
||||
nested = ChildSerializer()
|
||||
|
||||
def validate_nested(self, nested):
|
||||
# Raise parent-level (non-field) validation error
|
||||
raise ValidationError(["parent-level nested error"])
|
||||
|
||||
serializer = ParentSerializer(data={"nested": {"value": "ignored"}})
|
||||
assert not serializer.is_valid()
|
||||
|
||||
# Parent-level error is a list (current problematic case)
|
||||
assert serializer.errors["nested"] == ["parent-level nested error"]
|
||||
|
||||
# Access nested bound field
|
||||
parent_bound = serializer["nested"]
|
||||
|
||||
# Access child bound field – should not raise
|
||||
child_bound = parent_bound["value"]
|
||||
|
||||
# Core contract: errors must be a mapping, not None or list
|
||||
assert isinstance(child_bound.errors, dict)
|
||||
|
||||
# Sanity checks
|
||||
assert child_bound.value == "ignored"
|
||||
assert child_bound.name == "nested.value"
|
||||
|
||||
|
||||
class TestJSONBoundField:
|
||||
def test_as_form_fields(self):
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user