Django REST Serializer方法可写字段

Nic*_*ick 12 django rest serializer django-rest-framework

我正在阅读Django REST Framework,我有一个使用SerializerMethodField()与getter序列化的模型.

但是,当我POST到此端点时,我希望能够设置此字段,但这不起作用,因为正如上面的文档所示,您无法写入SerializerMethodField.Django REST中是否有任何方法可以为您定义自定义getter方法的序列化器字段,以及自定义setter方法?

编辑:这是我正在尝试做的事情的来源.客户与用户具有一对一的关系.

class ClientSerializer(serializers.ModelSerializer):
    email = serializers.SerializerMethodField()

    def create(self, validated_data):
        email = validated_data.get("email", None) # This doesn't work because email isn't passed into validated_data because it's a readonly field
        # create the client and associated user here


    def get_email(self, obj):
        return obj.user.email

    class Meta:
        model = Client
        fields = (
            "id",
            "email",
        )
Run Code Online (Sandbox Code Playgroud)

Jul*_*ins 10

这是一个读/写序列化器方法字段:

class ReadWriteSerializerMethodField(serializers.SerializerMethodField):
    def __init__(self, method_name=None, **kwargs):
        self.method_name = method_name
        kwargs['source'] = '*'
        super(serializers.SerializerMethodField, self).__init__(**kwargs)

    def to_internal_value(self, data):
        return {self.field_name: data}

Run Code Online (Sandbox Code Playgroud)

  • @hackks,因为调用的“__init__”将是“SerializerMethodField”的父级之一,而不是“ReadWriteSerializerMethodField”的父级之一 (2认同)

Dyl*_*sen 7

我尝试使用Guilherme Nakayama da SilvaJulio Marins的答案来解决写入 SerializerMethodField 的问题。它适用于阅读和更新,但不适用于创作。

所以我根据他们的答案创建了自己的 WritableSerializerMethodField,它非常适合阅读、创建和写作。

class WritableSerializerMethodField(serializers.SerializerMethodField):
    def __init__(self, **kwargs):
        self.setter_method_name = kwargs.pop('setter_method_name', None)
        self.deserializer_field = kwargs.pop('deserializer_field')

        super().__init__(**kwargs)

        self.read_only = False

    def bind(self, field_name, parent):
        retval = super().bind(field_name, parent)
        if not self.setter_method_name:
            self.setter_method_name = f'set_{field_name}'

        return retval

    def get_default(self):
        default = super().get_default()

        return {
            self.field_name: default
        }

    def to_internal_value(self, data):
        value = self.deserializer_field.to_internal_value(data)
        method = getattr(self.parent, self.setter_method_name)
        return {self.field_name: self.deserializer_field.to_internal_value(method(value))}
Run Code Online (Sandbox Code Playgroud)

然后我在我的序列化器中使用了它

class ProjectSerializer(serializers.ModelSerializer):
    contract_price = WritableSerializerMethodField(deserializer_field=serializers.DecimalField(max_digits=12, decimal_places=2))

    def get_contract_price(self, project):
        return project.contract_price

    def set_contract_price(self, value):
        return value
Run Code Online (Sandbox Code Playgroud)


zym*_*mud 6

您需要使用另一种类型的字段:

class ClientSerializer(serializers.ModelSerializer):
    email = serializers.EmailField(source='user.email')

    def create(self, validated_data):
        # DRF will create object {"user": {"email": "inputed_value"}} in validated_date
        email = validated_data.get("user", {}).get('email')

    class Meta:
        model = Client
        fields = (
            "id",
            "email",
        )
Run Code Online (Sandbox Code Playgroud)