Best practices for using @property with Enum values on a Django model for DRF serialization
Question: I'm looking for guidance on using @property on a Django model, particularly when the property returns an Enum value and needs to be exposed in a Django REST Framework (DRF) serializer. Here’s my setup:
I’ve defined an Enum, AccountingType, to represent the possible accounting types:
from enum import Enum
class AccountingType(Enum):
ASSET = "Asset"
LIABILITY = "Liability"
UNKNOWN = "Unknown"
On my Account model, I use a @property method to determine the accounting_type based on existing fields:
# 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
In Django views, I can use this property directly without issues. For example:
account = Account.objects.get(id=some_id)
if account.accounting_type == AccountingType.LIABILITY:
print("This account is a liability.")
Problem: When trying to expose accounting_type
in DRF, using serializers.ReadOnlyField()
does not include the property in the serialized output:
class AccountDetailSerializer(serializers.ModelSerializer):
accounting_type = serializers.ReadOnlyField()
class Meta:
model = Account
fields = ['accounting_type', 'account_id', ...]
I found that switching to serializers.SerializerMethodField()
resolves the issue, allowing me to return the Enum value as a string:
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
Questions:
- Is there a reason serializers.ReadOnlyField() doesn’t work with @property when it returns an Enum? Does DRF handle @property fields differently based on the return type?
- Is SerializerMethodField the recommended approach when a property returns a complex type, like an Enum, that needs specific serialization? Are there best practices for exposing Enum values via model properties in DRF?
Any insights would be appreciated.
Is there a reason serializers.ReadOnlyField() doesn’t work with @property when it returns an Enum?
An Enum can not be JSON serialized. Make the AccountingType
json serializable by making it a subclass of str
as well:
class AccountingType(str, Enum):
ASSET = 'Asset'
LIABILITY = 'Liability'
UNKNOWN = 'Unknown'
then it is sufficient to work with a ReadOnlyField
:
class AccountDetailSerializer(serializers.ModelSerializer):
accounting_type = serializers.ReadOnlyField()
# …
Alternatively, we can just obtain the .value
from the AccountingType
:
class AccountDetailSerializer(serializers.ModelSerializer):
accounting_type = serializers.ReadOnlyField(source='accountingtype.value')
# …