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)
Вернуться на верх