Skip to content

Fix DictField HTML input returning empty dict for missing fields#9891

Open
veeceey wants to merge 1 commit intoencode:mainfrom
veeceey:fix/issue-6234-dictfield-html-parsing
Open

Fix DictField HTML input returning empty dict for missing fields#9891
veeceey wants to merge 1 commit intoencode:mainfrom
veeceey:fix/issue-6234-dictfield-html-parsing

Conversation

@veeceey
Copy link

@veeceey veeceey commented Feb 8, 2026

Summary

Fixes #6234

parse_html_dict always returned an empty MultiValueDict when no matching keys were found in the HTML form input, making it impossible to distinguish between:

  • A field that was not specified in the form data
  • A field that was specified but had no values

This caused DictField to treat missing fields as if they contained an empty dict, breaking required, default, and partial update logic for multipart/form-data requests.

Changes

  • rest_framework/utils/html.py: Added a default parameter to parse_html_dict (consistent with how parse_html_list already works). Returns default when no matching keys are found in the input.
  • rest_framework/fields.py: Updated DictField.get_value to pass default=empty so that missing fields are correctly treated as not provided. Also updated DictField.to_internal_value to pass default=data so inner MultiValueDict data is preserved when no dot-separated sub-keys are found.
  • rest_framework/serializers.py: Updated Serializer.get_value to use the new default= parameter instead of or empty for consistency.
  • tests/test_fields.py: Added 4 new test cases for DictField HTML form input covering:
    • Valid dict input via QueryDict with dot-separated keys
    • Missing field with a default value
    • Missing field that is not required (should be skipped)
    • Missing field that is required (should fail validation)

Test plan

  • All existing DictField tests pass
  • All 4 new test cases pass
  • Full test_fields.py, test_serializer.py, and test_parsers.py suites pass (401 passed, 1 pre-existing failure unrelated to this change)
  • Verify in a real Django project with multipart/form-data requests that DictField partial updates work correctly

…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>
@veeceey
Copy link
Author

veeceey commented Feb 19, 2026

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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small detail, but can we please tweak these asserrt to show the serializer errors when they fail? That will give much better test output:

Suggested change
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)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't a better default be an empty dict here?

Suggested change
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):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks consistent with what we do for parsing html list 👍🏻 :

#5927

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 default parameter to parse_html_dict() to return a specified value when no matching keys are found (consistent with parse_html_list)
  • Updated DictField.get_value() and Serializer.get_value() to pass default=empty so missing fields are correctly detected
  • Updated DictField.to_internal_value() to pass default=data to 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DictField parsing for "html" inputs misleadingly returns an empty dict even if the field was not specified

2 participants

Comments