【问题标题】:DRF serializer parsing comma-delimited string into a list fieldDRF 序列化程序将逗号分隔的字符串解析为列表字段
【发布时间】:2022-01-18 07:37:21
【问题描述】:

有没有办法修改 DRF 序列化程序解析传入请求负载的方式?

我试图让客户端发送一个逗号分隔的列表作为查询参数,但在序列化程序中接收它作为一个列表,但 DRF 一直在抱怨。现在我手动拦截视图中的请求并手动解析该字段,然后将其传递给序列化程序,这对我来说似乎并不优雅。

我现在在做什么

class ExampleSerializer(...):
    list_field = serialzers.ListField(child=serializers.Integerfield(...))
    # more fields

def view(request):
    payload = request.GET
    payload["list_field"] = str(payload.get("list_field", "")).split(",")
    serializer = ExampleSerializer(data=payload)

我更喜欢什么(使用与上面相同的序列化程序)

def view(request):
   serializer = ExampleSerializer(data=request.GET)

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    ListField 将与 json 或多值查询字符串或表单主体一起使用(如下所示)。它不解析逗号分隔的字符串。

    This will work:
    GET /path/?list_field=1&list_field=2&list_field=3
    

    您需要一个自定义字段来实现您的解析逻辑:接受一个字符串并使用分隔符(,: 等)将其拆分,然后使用子字段对其进行验证。

    没有以这种方式工作的内置字段,但有一个很棒的example GIST here,您可以在编写自己的字段时复制或引用它。我从要点中包含了一些 sn-ps,但由于它不是我的,所以我不喜欢复制整个内容。

    # https://gist.github.com/imomaliev/77fdfd0ab5f1b324f4e496768534737e
    
    class CharacterSeparatedField(serializers.ListField):
        def __init__(self, *args, **kwargs):
            self.separator = kwargs.pop("separator", ",")
            super().__init__(*args, **kwargs)
    
        def to_internal_value(self, data):
            data = data.split(self.separator)
            return super().to_internal_value(data)
    
        # continues ...
    
    class TestCharacterSeparatedManyField:
        def test_field_from_native_should_return_list_for_given_str(self):
            field = CharacterSeparatedField(child=serializers.CharField())
            assert field.to_internal_value("a,b,c") == ["a", "b", "c"]
    

    您还可以编写自定义validate_{fieldname} 函数来修改该值。这至少将其保留在序列化程序中。不过,如果可能的话,适当的字段会更好,但这是一次性验证/转换的常见模式。

    class ExampleSerializer(Serializer):
        list_field = CharField()
    
        def validate_list_field(self, value):
            arr = value.split(",")
            arr = [int(x) for x in arr if x.isdigit()]
            if len(arr) == 0:
                raise ValidationError("Supply at least 1 value.")
            return arr
    

    【讨论】:

      猜你喜欢
      • 2010-09-12
      • 1970-01-01
      • 1970-01-01
      • 2018-04-20
      • 2013-02-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多