我的目标是将Django Rest框架中用户负载中特定字段中的所有字母大写。
模型如下:
class Order(models.Model):
class Item(models.TextChoices):
FIRST= 'FIRST', _('FIRST')
SECOND= 'SECOND', _('SECOND')
...
order_id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)
the_item = models.CharField(max_length=8, choices=Item.choices)
唯一允许的值是"FIRST"one_answers";SECOND"在大写。
我用这种方法来大写字母:
在Django Rest框架:
from rest_framework import serializers
class UpperCaseSerializerField(serializers.CharField):
def __init__(self, *args, **kwargs):
super(UpperCaseSerializerField, self).__init__(*args, **kwargs)
def to_representation(self, value):
value = super(UpperCaseSerializerField, self).to_representation(value)
if value:
return value.upper()
并在serializers.py中使用,如:
class OrderCreateSerializer(serializers.ModelSerializer):
#Force uppercase
item = UpperCaseSerializerField()
class Meta:
model = Order
fields = ['order_id', 'item' ]
这实际上是有效的,因为输入被转换为大写,但是,不再考虑模型约束.
有效载荷示例1:
{ "the_item": "first" } - LEGIT, converted in FIRST
有效载荷示例2:
{ "the_item": "FIRST" } - LEGIT, it's already uppercase
有效负载示例3:
{ "the_item": "1234567" } - COMPLETELY WRONG INPUT, but it is accepted! It should be not!
很明显,它只关心大写,完全忽略了模型结构,模型结构不承认与'FIRST'和'SECOND'不同的字符串。
因此,删除项= UpperCaseSerializerField()"restores"模型约束检查,但是我失去了将所有字母大写的能力。
我错过了什么吗?有办法两者兼得吗?
我认为显式声明序列化器字段会阻止序列化器为特定字段重用模型验证逻辑,正如您已经注意到的那样,因为可能在某些情况下您真的想要摆脱一些验证。
您可以通过为ChoiceFields创建另一个字段类来快速获得相同的验证,其中包含以下内容:
class UpperCaseSerializerChoiceField(serializers.ChoiceField):
def to_representation(self, value):
value = super().to_representation(value)
if value:
return value.upper()
并在序列化器上重新添加选项:
class OrderCreateSerializer(serializers.ModelSerializer):
item = UpperCaseSerializerChoiceField(choices=Order.Item.choices)
class Meta:
model = Order
fields = ['order_id', 'item' ]
注意,我没有尝试代码
编辑:根据源代码,方法to_internal_value
负责验证选择(这实际上是有意义的,在呈现数据时调用to_representation
,即。获取API响应)。
所以使用下面的东西应该会有帮助:
class UpperCaseSerializerChoiceField(serializers.ChoiceField):
def to_internal_value(self, data):
if data: # In case the field is nullable
data = data.upper()
return super().to_internal_value(data)