Фреймворк django rest, как переопределить поле так, чтобы "null было равно нулю"
Здравствуйте, у меня есть модель с полем, которое не является нулевым в базе данных - поле "сумма". Однако на уровне api это поле может быть пропущено, и тогда оно должно быть сохранено как значение по умолчанию.
Я перепробовал несколько способов, однако я продолжаю возвращаться к тому факту, что to_internal_value() не выполняется для полей, значение которых равно None? Даже если в поле allow_null указано значение 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))
Однако здесь утверждение не выполняется. И после исследования выясняется, что "to_internal_value" никогда не вызывается для полей "none". это просто короткое замыкание.
Как это преодолеть? И, если возможно, могу ли я вместо значения по умолчанию "0" установить значение по умолчанию "по умолчанию для определения модели"? Т.е. как будто значение опущено при создании модели?
Вместо создания пользовательского поля вы можете изменить его значение во время проверки.
Проверьте, работает ли это у вас
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
Но, честно говоря, я думаю, что в вашем коде есть какая-то другая проблема, которую вы пытаетесь решить странным образом
Вы переопределяете метод validate_empty_values()
, чтобы не видеть None
/null
как пустое значение, и, таким образом, вызываете .to_internal_value()
:
class NullIsZeroDecimalField(serializers.DecimalField):
def __init__(self, **kwargs):
super().__init__(allow_null=True, default=0, **kwargs)
def validate_empty_values(self, data):
if data is None:
return False, data
else:
return super().validate_empty_values(data)
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
"""
if data is None or data == "":
return Decimal(0)
return super().to_internal_value(data)
Как бы то ни было, я не думаю, что это хорошая идея: null
и 0
- это разные вещи. Я думаю, что в большинстве случаев катаморфизм, которым, по сути, является большинство преобразований, должен быть биективным.