如何使Serializer中的字段既可读又可写
How to make a field in Serializer both readable and writeable
我正在为我的模型编写一个序列化程序,它将使用 GET、POST 和 PATCH 端点进行访问。我的模型中有一个 属性,我将其用作字段的来源。但是,在序列化程序字段中使用 source=
使其成为只读状态。
如果我从
中删除 source="get_field1"
field1 = serializers.NullBooleanField(source="get_field1")
然后我就可以更新数据了。
但我必须使用源来获取字段的正确值。
class MyModel(models.Model):
field1 = NullBooleanField(default=None)
@property
get_field1(self):
data = True
# ...some logic
return data
现在我有一个正在使用的序列化器
class MyModelSerializer(serializers.ModelSerializer):
field1 = serializers.NullBooleanField(source="get_field1")
class Meta:
model = MyModel
fields = ('field1')
现在在我的 API 端点,我这样做
serializer = MyModelSerializer(my_model, data=request.data, partial=True)
if serializer.is_valid():
serializer.save() # <- throws error "can't set attribute"
此外,我想提一下,序列化程序中的字段是由 属性 名称而不是字段名称引用的。
示例:如果我这样做
>> serializer.validated_data
>> 'OrderedDict(['get_field1'], True) # <- shouldn't this by field1 and not get_field1
这可以通过覆盖序列化程序的 __init__()
方法来完成。除此之外,我们必须将一些 context
数据传递给序列化程序以区分 GET
、POST
和 PATCH
请求。
class MyModelSerializer(serializers.ModelSerializer):
<b>field1 = serializers.NullBooleanField() # remove "source" argument from here
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.context['request'].method == 'GET':
self.fields['field1'] =serializers.NullBooleanField(source= "get_field1")</b>
class Meta:
model = MyModel
fields = ('field1',)
并且在序列化数据时,不要忘记将请求作为上下文传递,如
serializer = MyModelSerializer(my_model, data=request.data, partial=True, <b>context={"request": request}</b>)
@JPG 的回答很好,但我觉得这是一种 hacky 方式。
我会覆盖 Serializer 的 to_representation
方法来实现您的目的。
您可以执行以下操作
class MyModelSerializer(serializers.ModelSerializer):
field1 = serializers.NullBooleanField() # get rid of source
def to_representation(self, instance):
data = super(MyModel, self).to_representation(instance)
data.update({
'field1': instance.get_field1
})
return data
class Meta:
model = MyModel
fields = ('field1')
这样您就隐式提供了源并且您的字段变得可写。因此,每次 GET、POST 或 PATCH 时,您都会获得正确的值。
我正在为我的模型编写一个序列化程序,它将使用 GET、POST 和 PATCH 端点进行访问。我的模型中有一个 属性,我将其用作字段的来源。但是,在序列化程序字段中使用 source=
使其成为只读状态。
如果我从
中删除source="get_field1"
field1 = serializers.NullBooleanField(source="get_field1")
然后我就可以更新数据了。
但我必须使用源来获取字段的正确值。
class MyModel(models.Model):
field1 = NullBooleanField(default=None)
@property
get_field1(self):
data = True
# ...some logic
return data
现在我有一个正在使用的序列化器
class MyModelSerializer(serializers.ModelSerializer):
field1 = serializers.NullBooleanField(source="get_field1")
class Meta:
model = MyModel
fields = ('field1')
现在在我的 API 端点,我这样做
serializer = MyModelSerializer(my_model, data=request.data, partial=True)
if serializer.is_valid():
serializer.save() # <- throws error "can't set attribute"
此外,我想提一下,序列化程序中的字段是由 属性 名称而不是字段名称引用的。
示例:如果我这样做
>> serializer.validated_data
>> 'OrderedDict(['get_field1'], True) # <- shouldn't this by field1 and not get_field1
这可以通过覆盖序列化程序的 __init__()
方法来完成。除此之外,我们必须将一些 context
数据传递给序列化程序以区分 GET
、POST
和 PATCH
请求。
class MyModelSerializer(serializers.ModelSerializer):
<b>field1 = serializers.NullBooleanField() # remove "source" argument from here
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if self.context['request'].method == 'GET':
self.fields['field1'] =serializers.NullBooleanField(source= "get_field1")</b>
class Meta:
model = MyModel
fields = ('field1',)
并且在序列化数据时,不要忘记将请求作为上下文传递,如
serializer = MyModelSerializer(my_model, data=request.data, partial=True, <b>context={"request": request}</b>)
@JPG 的回答很好,但我觉得这是一种 hacky 方式。
我会覆盖 Serializer 的 to_representation
方法来实现您的目的。
您可以执行以下操作
class MyModelSerializer(serializers.ModelSerializer):
field1 = serializers.NullBooleanField() # get rid of source
def to_representation(self, instance):
data = super(MyModel, self).to_representation(instance)
data.update({
'field1': instance.get_field1
})
return data
class Meta:
model = MyModel
fields = ('field1')
这样您就隐式提供了源并且您的字段变得可写。因此,每次 GET、POST 或 PATCH 时,您都会获得正确的值。