DRF 序列化程序将逗号分隔的字符串解析为列表字段

DRF serializer parsing comma-delimited string into a list field

有没有办法修改 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)

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

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

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

没有以这种方式工作的内置字段,但是有一个很好的 example GIST here,您可以在编写自己的字段时复制或参考它。我已经包含了要点中的一些片段,但由于它不是我的,所以我不愿意复制整个内容。

# 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}函数来修改这个值。这至少将它保留在序列化程序中。不过,如果可能的话,适当的 Field 会更好,但这是一次性 validation/transformations 的常见模式。

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