Django REST Framework - Пользовательский сериализатор переопределяет ограничения модели
Моя задача состоит в том, чтобы в Django Rest Framework.
капитализировать все буквы, поступающие в определенное поле из пользовательской полезной нагрузки.Вот модель:
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)
Единственными допустимыми значениями являются "ПЕРВЫЙ" и "ВТОРОЙ" в верхнем регистре.
Я использовал этот подход для написания букв заглавными буквами:
В Django Rest Framework:
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'.
Итак, удаление item = UpperCaseSerializerField() "восстанавливает" проверку ограничений модели, но я теряю возможность писать все буквы заглавными.
Я что-то упускаю? Есть ли способ сохранить оба варианта?
Я думаю, что явное объявление поля сериализатора не позволяет сериализатору повторно использовать логику валидации модели для этого конкретного поля, как вы уже заметили, потому что, возможно, в некоторых случаях вы действительно хотите избавиться от некоторой валидации.
Вы можете довольно быстро получить ту же валидацию, создав другой класс поля для 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)