Fix DictField HTML input returning empty dict for missing fields#9891
Fix DictField HTML input returning empty dict for missing fields#9891veeceey wants to merge 1 commit intoencode:mainfrom
Conversation
…input (encode#6234) When using DictField with HTML form (multipart/form-data) input, parse_html_dict always returned an empty MultiValueDict when no matching keys were found. This made it impossible to distinguish between an unspecified field and an empty input, causing issues with required/default field handling. This aligns parse_html_dict with parse_html_list by adding a default parameter that is returned when no matching keys are found. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Hi maintainers, friendly ping on this PR. It's been open for about 10 days without any review activity. Would really appreciate any feedback or direction when you get a chance. Happy to make adjustments if needed. Thank you! |
| # nested HTML forms. | ||
| if html.is_html_input(dictionary): | ||
| return html.parse_html_dict(dictionary, prefix=self.field_name) or empty | ||
| return html.parse_html_dict(dictionary, prefix=self.field_name, default=empty) |
There was a problem hiding this comment.
If I revert this change the tests still pass, so that tells me that this is no test for it, please add (at least) a test that fails on main and passes on this branch when this is added
| data = serializers.DictField(child=serializers.CharField()) | ||
|
|
||
| serializer = TestSerializer(data=QueryDict('data.a=1&data.b=2')) | ||
| assert serializer.is_valid() |
There was a problem hiding this comment.
Small detail, but can we please tweak these asserrt to show the serializer errors when they fail? That will give much better test output:
| assert serializer.is_valid() | |
| assert serializer.is_valid(), serializer.errors |
Some for the other assert serializer.is_valid() in the other tests
| """ | ||
| if html.is_html_input(data): | ||
| data = html.parse_html_dict(data) | ||
| data = html.parse_html_dict(data, default=data) |
There was a problem hiding this comment.
Wouldn't a better default be an empty dict here?
| data = html.parse_html_dict(data, default=data) | |
| data = html.parse_html_dict(data, default={}) |
|
|
||
|
|
||
| def parse_html_dict(dictionary, prefix=''): | ||
| def parse_html_dict(dictionary, prefix='', default=None): |
There was a problem hiding this comment.
Looks consistent with what we do for parsing html list 👍🏻 :
There was a problem hiding this comment.
Pull request overview
This pull request fixes a bug where DictField could not distinguish between a field that was not specified in HTML form data versus a field that was specified but had no values. This caused issues with required fields, default values, and partial updates when using multipart/form-data requests.
Changes:
- Added a
defaultparameter toparse_html_dict()to return a specified value when no matching keys are found (consistent withparse_html_list) - Updated
DictField.get_value()andSerializer.get_value()to passdefault=emptyso missing fields are correctly detected - Updated
DictField.to_internal_value()to passdefault=datato preserve inner MultiValueDict data when no nested keys exist - Added comprehensive test coverage for DictField HTML form input scenarios
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| rest_framework/utils/html.py | Added default parameter to parse_html_dict() to handle missing fields correctly |
| rest_framework/fields.py | Updated DictField.get_value() and to_internal_value() to use the new default parameter |
| rest_framework/serializers.py | Updated Serializer.get_value() to use explicit default=empty parameter for consistency |
| tests/test_fields.py | Added 4 test cases covering various DictField HTML form input scenarios |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
Fixes #6234
parse_html_dictalways returned an emptyMultiValueDictwhen no matching keys were found in the HTML form input, making it impossible to distinguish between:This caused
DictFieldto treat missing fields as if they contained an empty dict, breakingrequired,default, and partial update logic formultipart/form-datarequests.Changes
rest_framework/utils/html.py: Added adefaultparameter toparse_html_dict(consistent with howparse_html_listalready works). Returnsdefaultwhen no matching keys are found in the input.rest_framework/fields.py: UpdatedDictField.get_valueto passdefault=emptyso that missing fields are correctly treated as not provided. Also updatedDictField.to_internal_valueto passdefault=dataso inner MultiValueDict data is preserved when no dot-separated sub-keys are found.rest_framework/serializers.py: UpdatedSerializer.get_valueto use the newdefault=parameter instead ofor emptyfor consistency.tests/test_fields.py: Added 4 new test cases for DictField HTML form input covering:Test plan
test_fields.py,test_serializer.py, andtest_parsers.pysuites pass (401 passed, 1 pre-existing failure unrelated to this change)multipart/form-datarequests that DictField partial updates work correctly