【问题标题】:Custom field Choices error in Django rest frameworkDjango rest框架中的自定义字段选择错误
【发布时间】:2018-12-13 00:40:23
【问题描述】:

我目前在 Django Rest 框架中创建选择字段字段时遇到问题。起初,在 google 中寻找解决方案,我找到了在我的项目中应用该解决方案的最佳实践。但是,我遇到了应用程序中剩余的服务问题,将其作为呈现该领域的方式。由于我需要通过固定选项来操作信息,因此我必须遵循甚至为此创建特定序列化程序的方法。

在使用 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

【问题讨论】:

    标签: python django django-models django-rest-framework django-views


    【解决方案1】:

    增加类型的最大长度

        type = models.CharField(max_length=15, choices=DiscountTypes.choices(), default=DiscountTypes.PERC.value)
    

    【讨论】:

    • 它没有完全解决,我实现了选择类型的目标,但是我理解了问题。 Django 正在保存对象而不是它的值......在“DiscountType.VALUE”而不是“value_absolute”的情况下。这就是为什么他报告这个数字对于专栏来说太小了。
    【解决方案2】:
    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  
    

    【讨论】:

    • 非常感谢 Tarjet,但是,我需要选择里面的选项并为我的 REST API 发送 JSON。我已经在上面测试过这个解决方案,但无法编辑只是查看答案。
    【解决方案3】:

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

    我开发的示例框架是这样的:

    我的脚本

    # -*- 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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-22
      • 2016-05-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-18
      • 1970-01-01
      相关资源
      最近更新 更多