Fix DictField partial HTML omission handling#9906
Fix DictField partial HTML omission handling#9906Sebastianhayashi wants to merge 3 commits intoencode:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
Fixes Django REST framework’s DictField behavior for HTML/multipart inputs during partial updates so that an omitted dict field is treated as “missing” (sentinel empty) rather than an empty dict, preventing it from incorrectly appearing in validated_data.
Changes:
- Updated
DictField.get_value()to returnemptywhen HTML parsing yields no keys during partial updates. - Added a regression test covering the partial-update omission case for HTML input.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
rest_framework/fields.py |
Treats empty parsed HTML dict input as omitted (empty) when partial=True. |
tests/test_fields.py |
Adds regression test ensuring omitted HTML dict fields do not appear in validated_data on partial updates. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| if html.is_html_input(dictionary): | ||
| return html.parse_html_dict(dictionary, prefix=self.field_name) | ||
| value = html.parse_html_dict(dictionary, prefix=self.field_name) | ||
| if not value and getattr(self.root, 'partial', False): |
There was a problem hiding this comment.
DictField.get_value() still returns an empty dict for omitted HTML/multipart input when partial=False. That means omitted DictFields can bypass the normal empty sentinel handling (e.g., required=True won’t raise “required”, and required=False fields can incorrectly show up in validated_data as {}). Consider matching Serializer.get_value()/ListField.get_value() behavior by returning empty whenever parse_html_dict(...) is empty (e.g., ... or empty), not only on partial updates.
| if not value and getattr(self.root, 'partial', False): | |
| if not value: |
|
|
||
|
|
There was a problem hiding this comment.
The new regression test covers partial updates, but the underlying omission behavior for HTML dict input can also affect full updates and required=True fields (omitted field being treated as {} instead of missing). Add a complementary test case for partial=False (and ideally required=True) to lock in the expected behavior once DictField.get_value() is adjusted.
| def test_full_update_missing_required_html_dict_field_is_error(self): | |
| class TestSerializer(serializers.Serializer): | |
| field_name = serializers.DictField(required=True) | |
| serializer = TestSerializer(data=QueryDict(''), partial=False) | |
| assert not serializer.is_valid() | |
| assert 'field_name' in serializer.errors |
| def test_partial_update_does_not_include_missing_html_dict_field(self): | ||
| class TestSerializer(serializers.Serializer): | ||
| field_name = serializers.DictField(required=False) | ||
|
|
||
| serializer = TestSerializer(data=QueryDict(''), partial=True) | ||
| assert serializer.is_valid() | ||
| assert 'field_name' not in serializer.validated_data |
There was a problem hiding this comment.
Would be nice to increate test coverage... This test passes on the main branch, but breaks here:
def test_partial_update_can_clear_html_dict_field(self):
class TestSerializer(serializers.Serializer):
field_name = serializers.DictField(required=False)
serializer = TestSerializer(data=QueryDict('field_name='), partial=True)
assert serializer.is_valid()
assert 'field_name' in serializer.validated_data
Summary
Fix
DictFieldhandling for HTML form input on partial updates.When the field is omitted in multipart/HTML input,
DictField.get_value()currently returns{}and the serializer incorrectly treats the field as provided. This change returnsemptyfor partial updates when parsed HTML dict input is empty, so omitted fields stay omitted.Reproduction
Changes
rest_framework/fields.pyDictField.get_value(), for HTML input:parse_html_dictself.root.partialis true, returnemptytests/test_fields.pytest_partial_update_does_not_include_missing_html_dict_fieldValidation
Result:
3 passedRelated to #6234.