Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom Field Logic Bypass #2012

Open
deckar01 opened this issue Jul 18, 2022 · 4 comments
Open

Custom Field Logic Bypass #2012

deckar01 opened this issue Jul 18, 2022 · 4 comments
Labels

Comments

@deckar01
Copy link
Member

If you want to create a field that transforms None to a preset value, a custom field is required.

Currently the documentation for "Creating A Field Class" states:

To create a custom field class, create a subclass of marshmallow.fields.Field and implement its _serialize and/or _deserialize methods.

https://marshmallow.readthedocs.io/en/latest/custom_fields.html#creating-a-field-class

class Integer(fields.Integer):
    def _deserialize(self, value, *args, **kwargs):
        value = value or 0
        return super()._deserialize(value, *args, **kwargs)

class Test(Schema):
    foo = Integer(allow_none=True)

Test().load({'foo': None}) # but it produces {"foo": None} instead of {"foo": 0}

When None (or missing) is encountered _deserialize() is never executed, because Field.deserialize() returns immediately. The current work around appears to require an understanding of undocumented parts of the Field implementation and extending deserialize() instead. The documentation should probably explain the _/de/serialize() and None/missing interaction.

class Amount(fields.Integer):
    def deserialize(self, value, *args, **kwargs):
        value = value or 0
        return super(Amount, self).deserialize(value, *args, **kwargs)

A similar use case is having a Nested field supply the default values for the nested schema's fields when the parent field is None/missing. We may want to explore improving the default behavior in a future version, but for now providing a pattern for this in the docs would be helpful.

class Options(fields.Nested):
    def deserialize(self, value, *args, **kwargs):
        value = value or {}
        return super(Options, self).deserialize(value, *args, **kwargs)

Related to #388

@ThiefMaster
Copy link

Being able to use the load_default logic when receiving a None value would probably already cover many usecases...

@lafrech
Copy link
Member

lafrech commented Nov 29, 2023

Being able to use the load_default logic when receiving a None value would probably already cover many usecases...

I believe this is the point of #1381 (from #713 (comment)).

@ThiefMaster
Copy link

Yes, this would work perfectly fine for me! Any chance this will make it into a release soon-ish? :)

@lafrech
Copy link
Member

lafrech commented Nov 29, 2023

Any chance this will make it into a release soon-ish? :)

I won't be working on it in the coming weeks. If anyone wants to take over:

  • rework to load_default_values
  • add symmetrical dump_default_values
  • update __repr__
  • docs

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants