Как правильно создать сериалайзер для enum и настроить его отображение в drf_spectacular?

Здравствуйте! Я планирую разработать конструктор сериализаторов для перечислений (enum), который будет использоваться в представлениях (views) и для корректного отображения данных в Swagger, особенно в схемах. В текущей реализации я столкнулся с двумя проблемами:

1) У меня возникает ощущение, что логика реализована слишком сложно. Как можно упростить эту реализацию?
2) По какой-то причине Swagger подтягивает данные для схемы из другого перечисления, которое находится в другом приложении, а не из того, которое я передаю.

Вот пример моего перечисления:

```django
class EServicePlatform(models.IntegerChoices):
    ONLINE = 1, 'Онлайн'
    OFFLINE = 2, 'Оффлайн'
```

Это перечисление отправляется в представления в виде словаря:

```django
class DictionaryPlatforms(APIView):
    @extend_schema(responses={
        200: OpenApiResponse(response=DictionarySerializer(enum_class=EServicePlatform, many=True)),
        400: OpenApiResponse(description='Bad Request')}
    )
    def get(self, request, *args, **kwargs):
        data = [{"value": item.value, "label": item.label} for item in EServicePlatform]
        serializer = DictionarySerializer(data=data, many=True, enum_class=EServicePlatform)

        if serializer.is_valid():
            return Response(serializer.data, status=status.HTTP_200_OK)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
```

Также вот реализация самого конструктора сериализатора:

```django
class DictionarySerializer(serializers.Serializer):
    value = serializers.ChoiceField(choices=[])  # Зададим пустой список по умолчанию
    label = serializers.CharField()

    def __init__(self, *args
```

Не могли бы вы посоветовать, как можно решить эти проблемы?
  • 18 декабря 2024 г. 5:33
Ответы на вопрос 1
Здравствуйте!

Создание сериализаторов для перечислений (enum) и их корректное отображение в Swagger с использованием `drf_spectacular` может быть сделано более просто и понятно. Давайте разберем несколько аспектов:

### Упрощение реализации

1. **Используйте стандартные методы сериализаторов**: Вместо создания кастомного сериализатора для перечислений, можно использовать поле `ChoiceField` с автоматически подставляемыми значениями из перечислений.

2. **Определение `choices` для `ChoiceField`**: Вы можете передавать choices прямо в сериализатор через инициализацию, так чтобы не требуется ручная настройка.

### Исправление проблемы с отображением в Swagger

3. **Убедитесь, что схема правильно генерируется**: `drf_spectacular` должен понимать, что `ChoiceField` относится к вашему перечислению. Вам может понадобиться добавить правильные декораторы и настройки.

Вот обновленная версия вашего кода с учетом этих замечаний:

```python
# Ваше перечисление
class EServicePlatform(models.IntegerChoices):
    ONLINE = 1, 'Онлайн'
    OFFLINE = 2, 'Оффлайн'

# Сериализатор
class DictionarySerializer(serializers.Serializer):
    value = serializers.ChoiceField(choices=[(item.value, item.label) for item in EServicePlatform])
    label = serializers.CharField()

# Представление
class DictionaryPlatforms(APIView):
    @extend_schema(responses={
        200: OpenApiResponse(response=DictionarySerializer(many=True)),
        400: OpenApiResponse(description='Bad Request')}
    )
    def get(self, request, *args, **kwargs):
        data = [{"value": item.value, "label": item.label} for item in EServicePlatform]
        serializer = DictionarySerializer(data=data, many=True)

        if serializer.is_valid():
            return Response(serializer.data, status=status.HTTP_200_OK)
        else:
            return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
```

### Рекомендации по Swagger

Чтобы `drf_spectacular` правильно отображал ваше перечисление в схемах, важно, чтобы при использовании `ChoiceField` значения правильным образом отображались как Swagger enums.

Возможно, вам потребуется добавить классы-схемы для корректного отображения. Например:

```python
from drf_spectacular.utils import extend_schema_field
from rest_framework import serializers

@extend_schema_field(serializers.ChoiceField(choices=EServicePlatform.choices))
class EServicePlatformField(serializers.ChoiceField):
    pass
```

### Заключение

Эти изменения должны упростить ваш код и помочь с правильным отображением в Swagger. Если вы все еще видите, что Swagger подтягивает информацию из другого перечисления, убедитесь, что для вашего перечисления не используется другой сериализатор или не переопределены путаницы при регистрации схем в `drf_spectacular`.
Похожие вопросы