【问题标题】:Key error in Django Rest Framework when using serializers.ChoiceField with tuples使用带有元组的 serializers.ChoiceField 时 Django Rest Framework 中的关键错误
【发布时间】:2015-03-25 05:33:24
【问题描述】:

我正在使用 Django 1.7.7 和 Django Rest Framework 3.1.1。

当我序列化这个模型时

class Question(models.Model):
  QUESTION_TYPES = (
    (10,'Blurb'),
    (20,'Group Header'),
    (21,'Group Footer'),
    (30,'Sub-Group Header'),
    (31,'Sub-Group Footer'),
    (50,'Save Button'),
    (100,'Standard Question'),
    (105,'Text-Area Question'),
    (110,'Multiple-Choice Question'),
    (120,'Standard Sub-Question'),
    (130,'Multiple-Choice Sub-Question')
)
type = models.IntegerField(default=100,choices=QUESTION_TYPES)

使用这个视图集/序列化器:

class QuestionSerializer(serializers.ModelSerializer):
   type = serializers.ChoiceField(choices='QUESTION_TYPES')

   class Meta:
      model = Question    

class QuestionViewSet(viewsets.ModelViewSet):
   model = Question
   serializer_class = QuestionSerializer

   def get_queryset(self):
      return Question.objects.all()

我得到一个 KeyError '10'(或者任何 QUESTION_TYPES 键是第一个从 Questions 表中序列化的键)。

错误似乎是由 to_representation 中的 rest_framework/fields.py 抛出的 return self.choice_strings_to_values[six.text_type(value)]

有什么明显的我做错了吗?使用带有 serializer.ChoiceField 的元组有问题吗?

约翰

【问题讨论】:

  • 怎么样:ChoiceField(choices=Question.QUESTION_TYPES)?
  • 这具有不抛出错误的理想效果,但它仍然显示键而不是诸如“blurb”之类的文本。我也试过type = serializers.CharField(source='get_type_display'),虽然它正确显示了文本,而不是键,但它似乎是只读的。即使我尝试写密钥,我也无法终生写信。

标签: django django-rest-framework


【解决方案1】:

似乎ChoiceField 在尝试覆盖序列化程序本身的行为时遇到了一些问题。

您可以通过使用两个单独的字段来解决此问题:

class QuestionSerializer(serializers.ModelSerializer):
    type = serializers.ChoiceField(choices=Question.QUESTION_TYPES)
    type_display = serializers.CharField(source='get_type_display',
                                         read_only=True)

    class Meta:
        model = Question

【讨论】:

    【解决方案2】:

    这一切都归结为 ChoiceField 类中的 line。它使用了两次密钥。

    self.choice_strings_to_values = dict([
        (six.text_type(key), key) for key in self.choices.keys()
    ])
    

    您可以通过创建自己的字段序列化器来扩展 ChoiceField 类来更改此行为

    class DisplayChoiceFieldSerializers(serializers.ChoiceField):
        def __init__(self, *args, **kwargs):
            super(DisplayChoiceFieldSerializers, self).__init__(*args, **kwargs)
            self.choice_strings_to_values = dict([
                (six.text_type(key), unicode(value)) for key, value in self.choices.iteritems()
            ])
    

    【讨论】:

    • 你的课效果很好,就像我认为 ChoiceField 会工作一样。你知道是否已经报告了一个错误吗?这似乎是一个如此明显的错误,感觉就像我错过了一些东西。谢谢。
    • 实际上,在使用这个类一段时间后,我们恢复到常规实现,因为它使我们的javascript端更容易。所以我不认为这是一个错误,只是一个不同的用例。
    • 谢谢,这个解决方案对我有用。这是 Python 3 stackoverflow.com/a/35575125/727716 的代码
    【解决方案3】:

    Python 3 上的等价物

    self.choice_strings_to_values = dict([
        (six.text_type(key), str(value)) for key, value in self.choices.items()
    ])
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-08-07
      • 2019-07-27
      • 2017-06-03
      • 2017-01-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-12
      相关资源
      最近更新 更多