Django rest框架中的自定义字段Choices错误



我目前在Django Rest Framework中创建Choice字段时遇到问题。起初,我在谷歌上寻找解决方案,找到了在我的项目中应用该解决方案的最佳实践。然而,我在应用程序的剩余服务中遇到了问题,使它成为了展示该领域的方式。由于我需要通过固定的选项来操作信息,所以我必须遵循甚至为此创建特定序列化程序的方法。

在使用DRF的ChoiceField字段之前,我可以正确选择选项,但无法通过获取响应中变量的名称来演示值。我的愿望是显示变量的值,而不是名称。为此,我创建了以下结构:

我的脚本,名为choices.py

# Model custom using ENUM concept
from enum import Enum
from rest_framework import serializers
class ChoiceEnum(Enum):
@classmethod
def choices(cls):
return tuple((x.name, x.value) for x in cls)
#Serializer custom ChoicesField
class ChoicesField(serializers.Field):
def __init__(self, choices, **kwargs):
self._choices = choices
super(ChoicesField, self).__init__(**kwargs)
def to_representation(self, obj):
return self._choices[obj]
def to_internal_value(self, data):
return getattr(self._choices, data)

我的型号

class Discount(models.Model):
class DiscountTypes(ChoiceEnum):
VALUE = 'value_absolute'
PERC = 'percentual'
employee = models.ForeignKey(Employee, default=None)
type = models.CharField(max_length=5, choices=DiscountTypes.choices(), default=DiscountTypes.PERC.value)
value = models.IntegerField(default=0)
inception = models.DateField(default=datetime.now)
class Meta:
db_table = 'discounts'
app_label = 'db_teste'

我的视图集和序列化程序

class DiscountSerializer(serializers.ModelSerializer):
employee__id = serializers.PrimaryKeyRelatedField(
source='employee', queryset=Employee.objects.all())
employee__name = serializers.ReadOnlyField(source='employee.name')
# type = serializers.ChoiceField(choices=Discount.DiscountTypes.choices())
type = ChoicesField(choices=Discount.DiscountTypes)
inception = serializers.ReadOnlyField()
class Meta:
model = Discount
fields = ('id', 'employee__id', 'employee__name',
'type', 'value', 'inception')

class Discounts(viewsets.ModelViewSet):
allowed_methods = ('GET', 'PUT', 'POST', 'PATCH', 'HEAD', 'OPTIONS')
queryset = Discount.objects.all()
serializer_class = DiscountSerializer

以前,使用DRF的选择字段,我可以安静地注册。现在用我的解决方案,我不能输入任何数据,我得到以下错误:

DRF错误

(1406, "Data too long for column 'type' at row 1")

如何解决和改进我的代码?

PS:在我的项目中,我使用Django 1.9.4和DRF 3.6.3

增加类型的最大长度

type = models.CharField(max_length=15, choices=DiscountTypes.choices(), default=DiscountTypes.PERC.value)
Make it simple with following snippet,hope it will help.
# 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 = serializers.CharField(source='get_gender_display')
class Meta:
model = User
def get_gender(self,obj):
return obj.get_gender_display()  
# views.py
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer  

我找到了一个更好的解决方案,但我不得不重做字段和函数脚本的结构。

我开发的示例框架是:

我的脚本

# -*- coding: utf-8 -*-
# Utilizando ENUM no projeto.
from enum import Enum
from rest_framework import serializers
#So far I have not been able to make it work yet!!
class ChoiceEnum(Enum):
@classmethod
def choices(cls):
return tuple((x.name, x.value) for x in cls)
#Serializer custom
class DisplayChoiceField(serializers.ChoiceField):
def __init__(self, *args, **kwargs):
choices = kwargs.get('choices')
self._choices = OrderedDict(choices)
super(DisplayChoiceField, self).__init__(*args, **kwargs)
def to_representation(self, obj):
"""Used while retrieving value for the field."""
return self._choices[obj]

我的型号:

class Discount(models.Model):
#class DiscountTypes(ChoiceEnum):
#    VALUE = 'value_absolute'
#    PERC = 'percentual'
DiscountTypes = (
('VA', 'value_absolute'),
('PE', 'percentual'),
)
employee = models.ForeignKey(Employee, default=None)
#type = models.CharField(max_length=5, choices=DiscountTypes.choices(), default=DiscountTypes.PERC.value)
type = models.CharField(max_length=20, choices=DiscountTypes)
value = models.IntegerField(default=0)
inception = models.DateField(default=datetime.now)
class Meta:
db_table = 'discounts'
app_label = 'db_teste'

序列化程序和视图集

from aldar_ws.choices import ChoicesField, DisplayChoiceField
...
class DiscountSerializer(serializers.ModelSerializer):
employee__id = serializers.PrimaryKeyRelatedField(
source='employee', queryset=Employee.objects.all())
employee__name = serializers.ReadOnlyField(source='employee.name')
# type = serializers.ChoiceField(choices=Discount.DiscountTypes.choices())
type = DisplayChoiceField(choices=Discount.DiscountTypes)
inception = serializers.ReadOnlyField()
class Meta:
model = Discount
fields = ('id', 'employee__id', 'employee__name',
'type', 'value', 'inception')

class Discounts(viewsets.ModelViewSet):
allowed_methods = ('GET', 'PUT', 'POST', 'PATCH', 'HEAD', 'OPTIONS')
queryset = Discount.objects.all()
serializer_class = DiscountSerializer

最新更新