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