Since allow_null=True, the serializer can still validate and partially update even though partial=False
Description:
When using Django’s model and serializer as shown below, the FlowSerializer allows partial updates even when partial=False, due to allow_null=True for the flow_id field.
Model:
class Flow(models.Model):
flow_id = models.IntegerField(null=True)
flow_info = models.JSONField()
Serializer:
class FlowSerializer(serializers.ModelSerializer):
flow_id = serializers.IntegerField(allow_null=True, required=False)
class Meta:
model = Flow
fields = "__all__"
Input data:
FlowSerializer(instance, data={"flow_info": {"test":1}})
When the input data does not include the flow_id field, the serializer still passes validation, resulting in a partial update. This behavior is unexpected because partial=True is not used.
Source Code Insight: The relevant code in the Django REST framework source is:
def get_default(self):
"""
Return the default value to use when validating data if no input
is provided for this field.
If a default has not been set for this field then this will simply
raise `SkipField`, indicating that no value should be set in the
validated data for this field.
"""
if self.default is empty or getattr(self.root, 'partial', False):
# No default, or this is a partial update.
raise SkipField()
Questions:
- Why does the get_default method check getattr(self.root, 'partial', False)?
- Why does the serializer allow validation to pass in non-partial update scenarios, even when not all fields are provided?
- Shouldn’t the serializer require all fields to be provided when partial=False?
This behavior is causing confusion and leads to unintended partial updates. Any insights or clarification on this design choice would be greatly appreciated.
you are passing required=False in FlowSerializer . don't you think you should pass required=True for desired result ? for failing validation ? @fbozhang
you are passing required=False in FlowSerializer . don't you think you should pass required=True for desired result ? for failing validation ? @fbozhang I don't think it's necessary to make it required. Because it allows nulls, it supports non-required fields, and if I use
required=True, it can't be modified locally. I useflow_id = serializers.IntegerField(allow_null=True, required=False)just to express my question more clearly. In fact, when I useserializers.ModelSerializer, this field is originally a non-required parameter. You can refer to the historical versions of Django and find thatget_defaultis not what I expected at the beginning.From the comments, it can be seen that this is intentional. I want to know what went wrong at that time that led to such a change. @Himalaypatel75
you are passing required=False in FlowSerializer . don't you think you should pass required=True for desired result ? for failing validation ? @fbozhang I don't think it's necessary to make it required. Because it allows nulls, it supports non-required fields, and if I use
required=True, it can't be modified locally. I useflow_id = serializers.IntegerField(allow_null=True, required=False)just to express my question more clearly. In fact, when I useserializers.ModelSerializer, this field is originally a non-required parameter. You can refer to the historical versions of Django and find thatget_defaultis not what I expected at the beginning.From the comments, it can be seen that this is intentional. I want to know what went wrong at that time that led to such a change. @Himalaypatel75
Understanding the Behavior:
-
get_defaultMethod andpartialCheck:-
The
get_defaultmethod checks if thepartialattribute of the serializer's root (the serializer instance itself) isFalse. This logic determines whether the serializer is in partial update mode. -
If
partialisFalse, the method assumes that a complete set of data is expected, and any missing fields will be considered errors.
-
-
Allowing Validation to Pass:
-
The serializer allows validation to pass even when not all fields are provided because the
flow_idfield hasallow_null=True. This means that the field can be null or omitted in the input data without causing validation errors. -
The combination of
partial=Falseandallow_null=Truecreates a discrepancy: whilepartial=Falsesuggests a complete update,allow_null=Truepermits partial updates by allowing theflow_idfield to be omitted.
-
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.