在 Django 模型上使用 @property 和 Enum 值进行 DRF 序列化的最佳实践

问题描述 投票:0回答:1

问题:我正在寻找有关在 Django 模型上使用 @property 的指导,特别是当属性返回 Enum 值并且需要在 Django REST Framework (DRF) 序列化器中公开时。这是我的设置:

我定义了一个枚举,AccountingType,来表示可能的会计类型:

from enum import Enum

class AccountingType(Enum):
    ASSET = "Asset"
    LIABILITY = "Liability"
    UNKNOWN = "Unknown"

在我的 Account 模型中,我使用 @property 方法根据现有字段确定accounting_type:

# 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.")

问题: 当尝试在 DRF 中公开

accounting_type
时,使用
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

问题:

  1. 当它返回 Enum 时,serializers.ReadOnlyField() 不能与 @property 一起使用是否有原因? DRF 是否根据返回类型以不同方式处理@property 字段?
  2. 当属性返回需要特定序列化的复杂类型(例如 Enum)时,SerializerMethodField 是推荐的方法吗? 是否有通过 DRF 中的模型属性公开 Enum 值的最佳实践?

任何见解将不胜感激。

python python-3.x django django-rest-framework
1个回答
0
投票

Enum 无法进行 JSON 序列化。这就是问题所在,但我们可以从

.value
中获取
AccountingType
:

class AccountDetailSerializer(serializers.ModelSerializer):
    accounting_type = serializers.ReadOnlyField(source='accountingtype.value')

    # …
© www.soinside.com 2019 - 2024. All rights reserved.