【问题标题】:Return display_name in ChoiceField在 ChoiceField 中返回 display_name
【发布时间】:2016-04-04 16:57:07
【问题描述】:

我正在使用 ModelViewSetModelSerializer 在 DRF 中实现一些 REST API。我所有的 API 都使用 JSON 格式,而我的一些模型使用 ChoiceField 字段,如下所示:

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)

我的问题是,默认情况下,DRF 总是返回(并接受)这些 JSON 消息选择的键(请参阅here),但我想改用标签,因为我认为它更加一致和清晰了解谁将使用这些 API。有什么建议吗?

【问题讨论】:

    标签: json django django-rest-framework choicefield django-serializer


    【解决方案1】:

    除了重写您的序列化程序之外别无他法。请查看here,看看它是如何实现的。

    【讨论】:

    • 嗨,谢谢,我读了。它适用于获取资源,但不适用于创建/更新新实体,知道吗?
    • 哦,你还没有提到这一点......所以也许你可以在你的序列化程序中定义 ChoiceField serializer field ......
    【解决方案2】:

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

    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)
    

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

    【讨论】:

    • 您保存标签而不是密钥的任何原因?
    • @mariodev 我没有保存标签,在数据库中将存储密钥。我仅将标签用于与客户端通信,MyChoiceField 只是将值与键映射,反之亦然。我认为这种方式对于不必了解这些数据的内部表示的客户来说更容易理解。
    • 我想这对于您的特定情况是正确的。我只是不相信将标签(而不是密钥)传递给 to_internal_value 是最好的做法。一般来说,从客户端传递密钥表示会更有意义。除非这在您的情况下是不可能的,否则您的解决方案是可以接受的。 +1 ;)
    • 嗨@SimoV8答案有效,我只是想知道自从答案发布以来是否有更简单的方法来实现这一目标?
    【解决方案3】:

    以前的答案对我帮助很大,但对我没有用,因为我使用的是 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']
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-09-12
      • 2014-01-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-07
      • 1970-01-01
      相关资源
      最近更新 更多