简体   繁体   中英

Custom field Choices error in Django rest framework

I currently have a problem with creating a Choice field field in the Django Rest Framework. At first, looking for solutions in google, I found the best practices to apply the solution in my project. However, I came across problems in the service remaining from the application, bring it the way to present the field. Since I need to manipulate information through fixed options, I had to follow the methodology of even creating a specific serializer for this.

Before using the ChoiceField field of the DRF, I am able to correctly choose the option but cannot demonstrate the value by getting the name of the variable in the response. My wish is that the value and not the name of the variable to be displayed. For this I created the following structure:

My script, called 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)

My Model

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'

My Viewset and Serializer

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

Before, using DRF's choice field, I was able to register quietly. Now with my solution, I can not enter any data and I get this error below:

Error in DRF

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

How can I solve and improve my code?

PS: In my project, I use Django 1.9.4 and 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  

I was able to find a better solution, however, I had to redo the structure of my field and function script.

The example framework I developed was this:

My script :

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

My Model:

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'

Serializer and Viewset

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM