From cd2521e332ee48e5282b14024d02ae104da31495 Mon Sep 17 00:00:00 2001 From: Nix Date: Fri, 19 Jul 2024 01:56:10 +0700 Subject: [PATCH] Fix model field serializer with computed field (#1349) Co-authored-by: Sydney Runkle <54324534+sydney-runkle@users.noreply.github.com> --- src/serializers/computed_fields.rs | 14 +++++++++--- tests/serializers/test_model.py | 36 ++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/src/serializers/computed_fields.rs b/src/serializers/computed_fields.rs index 009f947dd..2d80d4f61 100644 --- a/src/serializers/computed_fields.rs +++ b/src/serializers/computed_fields.rs @@ -52,8 +52,12 @@ impl ComputedFields { // Do not serialize computed fields return Ok(()); } - for computed_fields in &self.0 { - computed_fields.to_python(model, output_dict, filter, include, exclude, extra)?; + for computed_field in &self.0 { + let field_extra = Extra { + field_name: Some(computed_field.property_name.as_str()), + ..*extra + }; + computed_field.to_python(model, output_dict, filter, include, exclude, &field_extra)?; } Ok(()) } @@ -83,12 +87,16 @@ impl ComputedFields { if extra.exclude_none && value.is_none() { continue; } + let field_extra = Extra { + field_name: Some(computed_field.property_name.as_str()), + ..*extra + }; let cfs = ComputedFieldSerializer { model, computed_field, include: next_include.as_ref(), exclude: next_exclude.as_ref(), - extra, + extra: &field_extra, }; let key = match extra.by_alias { true => computed_field.alias.as_str(), diff --git a/tests/serializers/test_model.py b/tests/serializers/test_model.py index c93825839..ddf9e5f97 100644 --- a/tests/serializers/test_model.py +++ b/tests/serializers/test_model.py @@ -565,6 +565,42 @@ def ser_x(self, v: Any, _) -> str: assert json.loads(s.to_json(Model(x=1000))) == {'x': '1_000'} +def test_function_plain_field_serializer_with_computed_field(): + @dataclasses.dataclass + class Model: + x: int + + @property + def computed_field_x(self) -> int: + return self.x + 200 + + def ser_func(self, v: Any, info: core_schema.FieldSerializationInfo) -> str: + return info.field_name + '_' + str(v * 2) + + field_str_with_field_serializer = core_schema.str_schema( + serialization=core_schema.plain_serializer_function_ser_schema( + Model.ser_func, + is_field_serializer=True, + info_arg=True, + return_schema=core_schema.any_schema(), + ) + ) + + s = SchemaSerializer( + core_schema.model_schema( + Model, + core_schema.model_fields_schema( + {'x': core_schema.model_field(field_str_with_field_serializer)}, + computed_fields=[ + core_schema.computed_field('computed_field_x', field_str_with_field_serializer), + ], + ), + ) + ) + assert json.loads(s.to_json(Model(x=1000))) == {'x': 'x_2000', 'computed_field_x': 'computed_field_x_2400'} + assert s.to_python(Model(x=2000)) == {'x': 'x_4000', 'computed_field_x': 'computed_field_x_4400'} + + def test_function_wrap_field_serializer_to_json(): @dataclasses.dataclass class Model: