【问题标题】:Django Rest Framework: get_FOO_display in serializer not letting me POSTDjango Rest Framework:序列化程序中的 get_FOO_display 不允许我发布
【发布时间】:2018-05-24 09:59:48
【问题描述】:

我最近在我的序列化程序中添加了一个source='get_fieldname_display。它非常适合获取 choices 元组的显示值,但现在我无法再使用 API 端点发布数据而不会出现错误:

TypeError: 'get_fieldname_display' is an invalid keyword argument for this function

需要明确的是,序列化程序的添加具体是这一行:

fieldName = serializers.CharField(source='fieldName_display')

我知道这行是导致问题的原因,因为当我将其注释掉时,我可以毫无问题地发布数据。但是,我需要这一行,以便在获取数据时可以从 choices 元组中获取显示名称。

我认为如果我使用两种不同的序列化程序(一种用于 GET,另一种用于 POST),问题可能会得到解决,但我不知道该怎么做——我在 views.py 中使用了generics.ListCreateAPIView .

编辑:

我的模型如下所示:

class MakeObjects(models.Model):

    FIELD_NAME_CHOICES = (
        ("01", "Choice 1"), 
        ("02", "Choice 2"), 
    )

    fieldname = CharField(choices = FIELD_NAME_CHOICES)

我的序列化器如下所示:

class ObjectSerializer(serializers.ModelSerializer): 
       fieldname = serializers.CharField(source='get_fieldname_display')
       class Meta:
           model = MakeObjects
           fields = ('__all__')

【问题讨论】:

  • 你在models.py中的fieldName是一个有选择的IntegerField?
  • 您可以将该特定字段设置为required=False
  • 我不认为问题出在模型上,我认为问题出在序列化程序上。基本上,我的目标是将“get_FOO_display”呈现为 JSON——但这样做是通过添加我的问题中提到的代码行——我不能再使用相同的序列化程序发布数据。也许快速修复是使用两个不同的序列化程序?一个用于获取,另一个用于发布?不过我不知道该怎么做。
  • @VijeshVenugopal,我将required=False 添加到序列化器中,但我使用的模型需要该字段才能创建一个新对象——这就是我在发布时所做的。我的错,我应该提前指定。

标签: python django django-rest-framework


【解决方案1】:

您可以尝试在以下位置添加新字段:

read_only_fields = ['fieldName']

【讨论】:

    【解决方案2】:

    为此,您需要自定义序列化器字段。

    这是 python 3 的 sn-p:

    class DisplayNameWritableField(serializers.ChoiceField):
        def __init__(self, **kwargs):
            self.html_cutoff = kwargs.pop('html_cutoff', self.html_cutoff)
            self.html_cutoff_text = kwargs.pop('html_cutoff_text', self.html_cutoff_text)
    
            self.allow_blank = kwargs.pop('allow_blank', False)
            super(ChoiceField, self).__init__(**kwargs)
    
        def to_representation(self, value):
            return self.choices.get(value, value)
    
        def bind(self, field_name, parent):
            super().bind(field_name, parent)
            self.choices = parent.Meta.model._meta.get_field(field_name).choices
    

    然后:

    class YourModelSerializer(serializers.ModelSerializer):
        your_choiced_model_field = DisplayNameWritableField()
    

    虽然这有点 hacky,所以并不是所有的自动文档引擎都能正确检测到选择,即使这工作得很好。

    您可能还喜欢https://github.com/encode/django-rest-framework/issues/1755

    【讨论】:

      猜你喜欢
      • 2021-09-08
      • 1970-01-01
      • 2019-08-27
      • 2017-01-16
      • 2016-12-18
      • 2017-06-04
      • 1970-01-01
      • 1970-01-01
      • 2019-04-01
      相关资源
      最近更新 更多