marshmallow icon indicating copy to clipboard operation
marshmallow copied to clipboard

Apply an attribute to all fields by default in marshmallow

Open codectl opened this issue 3 years ago • 3 comments

Is it possible to add an attribute by default to a Marshmallow schema?

For instance, I would like to create a deserialisation only schema. That would imply adding load_only to every field. Find an example below:

class Fruits(Schema)
    apple = fields.Str(load_only=True)
    banana = fields.Str(load_only=True)
    pineapple = fields.Str(load_only=True)
    pear = fields.Str(load_only=True)
    ...

Is that a more elegant way of going about this?

codectl avatar Aug 03 '22 07:08 codectl

I was able to come up with the following:

class Fruits(Schema)
    apple = fields.Str()
    banana = fields.Str()
    pineapple = fields.Str()
    pear = fields.Str()

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        for field in self.declared_fields.values():
            field.load_only = True

Now one could simply isolate that "ugly" attribute setter:

class DeserializerSchema(Schema):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        for field in self.declared_fields.values():
            field.load_only = True

class Fruits(DeserializerSchema)
    ...

An alternative way would even use the Meta class (documentation here):

class Fruits(Schema)
    apple = fields.Str()
    banana = fields.Str()
    pineapple = fields.Str()
    pear = fields.Str()

    class Meta:
       load_only = ("apple", "banana", "pineapple", "pear")

I personally don't like much this option since it requires statically adding each field to the list/tuple in the Meta class. Would be nice if there was a selector, like:

class Meta:
    load_only = "ALL"

codectl avatar Aug 03 '22 09:08 codectl

I would like to create a deserialisation only schema

Can you expand on what exactly you think should happen when the schema is serialized? Setting everything to load_only will make the schema silently dump an empty dict. This is something you could implement by extending the schema, and refactor into a decorator for reuse.

class Fruits(Schema)
    ...
    def dump(self, *args, **kwargs):
        raise NotImplementedError(...)
def load_only(cls):
    def no_dump(*args, **kwargs):
        raise NotImplementedError(...)
    cls.dump = no_dump
    return cls

@load_only
class Fruits(Schema):
    ...

Is it possible to add an attribute by default to a Marshmallow schema?

Currently there is no way to force all of the fields in a schema to inherit a property from the schema.

I don't see this use case as a strong argument for expanding this API. Rebuilding field instances with additional arguments is messy. See Nested.schema() for an example.

deckar01 avatar Aug 04 '22 14:08 deckar01

Can you expand on what exactly you think should happen when the schema is serialized?

I haven't really thought about it. But like you said, it silently dumps an empty dict and I guess that's an acceptable behavior. I am quite satisfied with the my __init__ override but your decorator idea is also well thought, perhaps I could merge them both.

I came up with this need and was wondering if there was a native way of achieving this. If any of this will be rolled out in a future release, then I can use the native approach.

codectl avatar Aug 04 '22 15:08 codectl