Django rest framework, how to override a field so that "null is zero"
Hello I have a Model with a field that is not null on the database -the field "amount". However on the api-level this field can be skipped, which should then be stored as the default value.
I have tried several ways, however I keep coming back to the fact that to_internal_value() isn't executed for fields when the value is None? Even though the field has allow_null to be True?
class NullIsZeroDecimalField(serializers.DecimalField):
def __init__(self, **kwargs):
super().__init__(allow_null=True, default=0, **kwargs)
def to_internal_value(self, data: Primitive) -> Decimal:
"""Convert None or empty strings to 0 before validation.
:param Primitive data: the input data
return Decimal: decimal value
"""
print('internal value')
if data is None or data == "":
return Decimal(0)
return super().to_internal_value(data)
class ModelWithAmountSerializer(serializers.ModelSerializer):
amount = NullIsZeroDecimalField(max_digits=20, decimal_places=10)
class Meta:
model = AmountModel
fields = ("amount",)
def test_serializer(self):
serializer = ReceiptLineSerializer(data={"amount": None})
is_valid = serializer.is_valid()
self.assertEqual(serializer.validated_data["amount"], Decimal(0))
However here the assertion fails. And upon research it turns out that the "to_internal_value" is never called for "none" fields. it is just short-circuited.
How to overcome this? And if possible, could I instead of defaulting to "0" default to the "default-of-the-model-definition"? IE as if the value is omitted when creating the model?
Instead creating custom field you can change its value during validation.
Check if this works for you
class ModelWithAmountSerializer(serializers.ModelSerializer):
amount = DecimalField(allow_null=True, allow_blank=True, default=0, max_digits=20, decimal_places=10)
class Meta:
model = AmountModel
fields = ("amount",)
def validate_amount(self, value):
if not value: # covers both None and ""
value = Decimal(0)
return value
But to be honest I think there is some other issue with your code that you are trying to solve in a weird way