Django 中經常要用到選項字段python
爲了提升數據庫效率和用戶可讀性,咱們實際存儲的是整數,顯示的時候以字符串顯示。
這個屬性在 Django Admin 獲得了很好的處理,但到了 Django Rest Framework 就不會自動轉化了。
下面的在GET的時候顯示字符串,但這個字段就變成只讀但了。數據庫
# models.py class User(AbstractUser): GENDER_CHOICES = ( ('M', 'Male'), ('F', 'Female'), ) gender = models.CharField(max_length=1, choices=GENDER_CHOICES) # serializers.py class UserSerializer(serializers.ModelSerializer): # 自定義了gender 字段,該字段變成只讀的了。 gender = serializers.CharField(source='get_gender_display') class Meta: model = User # viewsets.py class UserViewSet(viewsets.ModelViewSet): queryset = User.objects.all() serializer_class = UserSerializer
這裏涉及到一個有趣的實例方法: get_FOO_display
對於模型中含有 ++choices++ 參數的字段, FOO 是字段的名字, get_FOO_display() 返回選項的可讀字符串
要實現 model 中的 Choice Field, 在 GET 的時候顯示選項名字,在POST的時候既能字符串又能接受IDdjango
接受下面singo評論的建議:參考 stackoverflow 最佳方法以下:rest
class CommonInfoSerializer(serializers.ModelSerializer): .... def to_representation(self, instance): data = super().to_representation(instance) data.update(status=instance.get_status_display()) return data
完美解決 🔚code
如下其餘方法在更復雜的狀況下才考慮,能夠忽略orm
好比模型中有個status繼承
# models.py class CommonInfo(models.Model): INACTIVE = 0 PUBLISHED = 1 PENDING = -1 DRAFT = -2 REPORTED = -3 DELETED = -4 STATUS_CHOICES = ( (INACTIVE, 'INACTIVE'), (PUBLISHED, 'PUBLISHED'), (PENDING, 'PENDING'), (DRAFT, 'DRAFT'), (REPORTED, 'REPORTED'), (DELETED, 'DELETED'), ) status = models.SmallIntegerField( choices=STATUS_CHOICES, default=PUBLISHED)
# utils.py from rest_framework import serializers from collections import OrderedDict class ChoiceDisplayField(serializers.Field): """Custom ChoiceField serializer field.""" def __init__(self, choices, **kwargs): """init.""" self._choices = OrderedDict(choices) super(ChoiceDisplayField, self).__init__(**kwargs) # 返回可讀性良好的字符串而不是 1,-1 這樣的數字 def to_representation(self, obj): """Used while retrieving value for the field.""" return self._choices[obj] def to_internal_value(self, data): """Used while storing value for the field.""" for i in self._choices: # 這樣不管用戶POST上來可是CHOICES的 Key 仍是Value 都能被接受 if i == data or self._choices[i] == data: return i raise serializers.ValidationError("Acceptable values are {0}.".format(list(self._choices.values())))
# serializers.py from utils import ChoiceDisplayField class CommonInfoSerializer(serializers.ModelSerializer): INACTIVE = 0 PUBLISHED = 1 PENDING = -1 DRAFT = -2 REPORTED = -3 DELETED = -4 STATUS_CHOICES = ( (INACTIVE, 'INACTIVE'), (PUBLISHED, 'PUBLISHED'), (PENDING, 'PENDING'), (DRAFT, 'DRAFT'), (REPORTED, 'REPORTED'), (DELETED, 'DELETED'), ) status = ChoiceDisplayField(choices=STATUS_CHOICES)
to_internal_value()
了。from rest_framework import serializers from collections import OrderedDict class ChoiceDisplayField(serializers.ChoiceField): """Custom ChoiceField serializer field.""" def __init__(self, choices, **kwargs): """init.""" self._choices = OrderedDict(choices) super(ChoiceDisplayField, self).__init__(**kwargs) # 返回可讀性良好的字符串而不是 1,-1 這樣的數字 def to_representation(self, obj): """Used while retrieving value for the field.""" return self._choices[obj]
參考