Validate upload_file + data_source conflict for multipart requests

DRF 3.16 Serializer.get_value() uses parse_html_dict() or empty for all
HTML/multipart input. A flat key like data_source=2 produces an empty
dict ({}), which is falsy, so it falls back to empty and the nested
field is silently skipped. data.get('data_source') is therefore always
None in multipart requests, bypassing the conflict check.

Fix: also check self.initial_data for data_source and data_file in all
three guards in validate(), so the raw submitted value is detected even
when DRF's HTML parser drops the deserialized object.

Add test_upload_with_data_source_fails to cover the multipart conflict
path explicitly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Arthur
2026-03-30 15:35:28 -07:00
parent c5d911c48b
commit 3bd2dbea86
2 changed files with 23 additions and 3 deletions

View File

@@ -44,15 +44,20 @@ class ScriptModuleSerializer(ValidatedModelSerializer):
if upload_file is not None:
data['upload_file'] = upload_file
if upload_file and data.get('data_file'):
# For multipart requests, nested serializer fields (data_source, data_file) are
# silently dropped by DRF's HTML parser, so also check initial_data for raw values.
has_data_file = data.get('data_file') or self.initial_data.get('data_file')
has_data_source = data.get('data_source') or self.initial_data.get('data_source')
if upload_file and has_data_file:
raise serializers.ValidationError(
_("Cannot upload a file and sync from an existing data file.")
)
if upload_file and data.get('data_source'):
if upload_file and has_data_source:
raise serializers.ValidationError(
_("Cannot upload a file and sync from a data source.")
)
if self.instance is None and not upload_file and not data.get('data_file') and not data.get('data_source'):
if self.instance is None and not upload_file and not has_data_file and not has_data_source:
raise serializers.ValidationError(
_("Must upload a file or provide a data source or data file to sync.")
)