Skip to content

Comments

Fix allow_null=True fields skipped from validated_data when partial=False#9898

Closed
suportly wants to merge 1 commit intoencode:mainfrom
suportly:fix/9501-allow-null-partial-false
Closed

Fix allow_null=True fields skipped from validated_data when partial=False#9898
suportly wants to merge 1 commit intoencode:mainfrom
suportly:fix/9501-allow-null-partial-false

Conversation

@suportly
Copy link

Description

Fixes an issue where serializer fields with allow_null=True and required=False (but no explicit default) are silently omitted from validated_data when partial=False, effectively allowing unintended partial updates.

refs #9501

Root Cause

In Field.validate_empty_values(), when input data is missing (empty), partial=False, and required=False, the method calls self.get_default(). Since allow_null=True does not set an explicit default value, get_default() raises SkipField, and the field is silently omitted from validated_data — identical to partial=True behavior.

Fix

In validate_empty_values(), catch SkipField from get_default() and return (True, None) when the field has allow_null=True. This ensures nullable fields appear in validated_data during full (non-partial) updates. For non-nullable fields, existing behavior is preserved (re-raise SkipField).

# Before
return (True, self.get_default())

# After
try:
    return (True, self.get_default())
except SkipField:
    if self.allow_null:
        return (True, None)
    raise

Test plan

  • Added 6 new test cases in TestAllowNullNotRequiredInclusions:
    • Missing nullable field on create → included as None
    • Missing nullable field on full update → included as None
    • Missing nullable field on partial update → still skipped (preserved)
    • Explicit null value → works as before
    • Explicit default takes precedence over None
    • Non-nullable required=False → still skipped (preserved)
  • All 1476 existing tests pass with no regressions
  • All 6 new tests pass

🤖 Generated with Claude Code

…tial=False

When a field has allow_null=True and required=False but no explicit default,
omitting it from input data with partial=False would silently skip it from
validated_data, effectively allowing unintended partial updates.

The fix catches SkipField from get_default() in validate_empty_values() and
returns None for nullable fields, ensuring they appear in validated_data
during full (non-partial) updates.

Refs encode#9501

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
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 serializer fields with allow_null=True and required=False (but no explicit default) were being silently omitted from validated_data during full updates (partial=False), causing unintended partial update behavior. The fix ensures these nullable fields are included in validated_data with a None value during full updates, while preserving the existing behavior for partial updates.

Changes:

  • Modified Field.validate_empty_values() to catch SkipField exceptions and return None for nullable fields during full updates
  • Added comprehensive test coverage with 6 new test cases covering create, update, partial update, explicit null, explicit default, and non-nullable scenarios

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
rest_framework/fields.py Added try-except block in validate_empty_values() to handle SkipField from get_default() and return (True, None) for fields with allow_null=True
tests/test_serializer.py Added TestAllowNullNotRequiredInclusions test class with 6 comprehensive test cases validating the fix across different scenarios

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@auvipy auvipy self-requested a review February 23, 2026 06:56
@browniebroke
Copy link
Member

Thanks for raising this old issue to my attention again. Closing as per: #9501 (comment)

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.

3 participants