Лучшие практики использования @property со значениями Enum в модели Django для сериализации DRF
Вопрос: Я ищу руководство по использованию @property в модели Django, особенно когда свойство возвращает значение Enum и должно быть представлено в сериализаторе Django REST Framework (DRF). Вот моя установка:
Я определил Enum, AccountingType, для представления возможных типов учета:
from enum import Enum
class AccountingType(Enum):
ASSET = "Asset"
LIABILITY = "Liability"
UNKNOWN = "Unknown"
В моей модели счета я использую метод @property для определения типа_бухгалтерии на основе существующих полей:
# Account fields ...
@property
def accounting_type(self) -> AccountingType:
"""Return the accounting type for this account based on the account sub type."""
if self.account_sub_type in constants.LIABILITY_SUB_TYPES:
return AccountingType.LIABILITY
if self.account_sub_type in constants.ASSET_SUB_TYPES:
return AccountingType.ASSET
return AccountingType.UNKNOWN
В представлениях Django я могу использовать это свойство напрямую без проблем. Например:
account = Account.objects.get(id=some_id)
if account.accounting_type == AccountingType.LIABILITY:
print("This account is a liability.")
Проблема: При попытке выставить accounting_type
в DRF, использование serializers.ReadOnlyField()
не включает свойство в сериализованный вывод:
class AccountDetailSerializer(serializers.ModelSerializer):
accounting_type = serializers.ReadOnlyField()
class Meta:
model = Account
fields = ['accounting_type', 'account_id', ...]
Я обнаружил, что переход на serializers.SerializerMethodField()
решает проблему, позволяя мне возвращать значение Enum в виде строки:
class AccountDetailSerializer(serializers.ModelSerializer):
accounting_type = serializers.SerializerMethodField()
class Meta:
model = Account
fields = ['accounting_type', 'account_id', ...]
def get_accounting_type(self, obj):
return obj.accounting_type.value # Return the Enum value as a string
Вопросы:
- Есть ли причина, по которой serializers.ReadOnlyField() не работает с @property, когда он возвращает Enum? DRF по-разному обрабатывает поля @property в зависимости от возвращаемого типа?
- Является ли SerializerMethodField рекомендуемым подходом, когда свойство возвращает сложный тип, такой как Enum, который нуждается в специфической сериализации? Существуют ли лучшие практики для раскрытия значений Enum через свойства модели в DRF?
Любые соображения будут оценены по достоинству.
Есть ли причина, по которой serializers.ReadOnlyField() не работает с @property, когда он возвращает Enum?
Enum не может быть сериализован в JSON. Сделайте AccountingType
сериализуемым в JSON, сделав его подклассом str
, а также:
class AccountingType(str, Enum):
ASSET = 'Asset'
LIABILITY = 'Liability'
UNKNOWN = 'Unknown'
, то достаточно работать с ReadOnlyField
:
class AccountDetailSerializer(serializers.ModelSerializer):
accounting_type = serializers.ReadOnlyField()
# …
Альтернативно, мы можем просто получить .value
из AccountingType
:
class AccountDetailSerializer(serializers.ModelSerializer):
accounting_type = serializers.ReadOnlyField(source='accountingtype.value')
# …
Если вы часто работаете с Enum, вы можете создать пользовательское поле DRF для обработки сериализации Enum:
class EnumField(serializers.Field):
def to_representation(self, value):
return value.value if isinstance(value, Enum) else value
def to_internal_value(self, data):
raise NotImplementedError("EnumField is read-only.")
Случай использования:
class AccountDetailSerializer(serializers.ModelSerializer):
accounting_type = EnumField()
class Meta:
model = Account
fields = ['accounting_type', 'account_id', ...]