2

I'm implementing some REST API in DRF with ModelViewSet and ModelSerializer. All my APIs use the JSON format and some of my models use ChoiceField field, like that:

MyModel(models.Model):
     KEY1 = 'Key1'
     KEY2 = 'Key2'
     ATTRIBUTE_CHOICES = (
         (KEY1, 'Label 1'),
         (KEY2, 'Label 2'))
     attribute = models.CharField(max_length=4, 
                                  choices=ATTRIBUTE_CHOICES, default=KEY1)

My problem is that by default DRF always returns (and accept) the key of these choices for JSON messages (see here), but I would like to use the label instead, because I think it's more consistent and clear to unterstand for who will use those APIs. Any suggestion?

4

3 回答 3

5

我找到了一个可能的解决方案,即定义我自己的字段如下:

class MyChoiceField(serializers.ChoiceField):

    def to_representation(self, data):
        if data not in self.choices.keys():
            self.fail('invalid_choice', input=data)
        else:
            return self.choices[data]

    def to_internal_value(self, data):
        for key, value in self.choices.items():
            if value == data:
                 return key
        self.fail('invalid_choice', input=data)

它的工作方式与 to 相同ChoiceField,但返回并接受标签而不是键。

于 2015-12-30T21:21:32.543 回答
1

除了覆盖您的序列化程序之外别无他法。请看这里,看看它是如何做到的。

于 2015-12-30T18:49:51.467 回答
1

以前的答案对我帮助很大,但对我没有用,因为我使用 Django 版本 3 和 DRF 版本 3.11 ,所以我想出了这个:

# models.py
class Ball(models.Model):
    
    class Types(models.TextChoice):
        VOLLYBALL = 'VB', gettext_lazy('VollyBall')
        FOOTBALL = 'FB', gettext_lazy('FootBall')

    type = models.CharField(max_length=2, choices=Types.choices)
# serializers.py

class CustomChoiceField(serializers.ChoiceField):

    def to_representation(self, value):
        if value in ('', None):
            return value

        choice_dict = {str(key): key.label for key in self.choices}
        return choice_dict.get(str(value), value)

    def to_internal_value(self, data):
        if data == '' and self.allow_blank:
            return ''

        try:
            choice_dict = {key.label: str(key) for key in self.choices}
            return choice_dict[str(data)]
        except KeyError:
            self.fail('invalid_choice', input=data)

class BallSerializer(serializers.ModelSerializer):
    type = CustomChoiceField(choices=Book.Types)
    
    class Meta:
        model = Book
        fields = ['type']

于 2020-06-29T16:04:16.317 回答