4

I'm using Flask with flask-restful and webargs (which uses Marshmallow as its backend). Currently I'm able to pull in fields I want with this:

class AddGroup(Resource):
    args = {
        'name': fields.Str(missing=None),
        'phone': fields.Str(missing=None),
    }

    @use_args(args)
    def get(self, args):
        name = args['name'].strip()
        # ... some GET-related code ...

    @use_args(args)
    def post(self, args):
        name = args['name'].strip()
        # ... some POST-related code ...

So far so good. But what I'd really like to do is make sure that args['name'] comes into the various methods ("post", "get", etc.) with whitespace already stripped, so I don't have to process each variable manually each time. (stripping whitespace is just an example - it may be some other simple or complex transformation)

Is there a way (either by overriding the String field, defining my own field, or whatever) that will allow the args to be pre-processed before they arrive in the class methods?

Community
  • 1
  • 1
David White
  • 1,763
  • 2
  • 16
  • 27

2 Answers2

2

Since webargs are using marshmallow to make schema, you can use pre_load or post_load. There is example with "slugify" a string in the docs of marshmallow:

from marshmallow import Schema, fields, pre_load

class UserSchema(Schema):
    name = fields.Str()
    slug = fields.Str()

    @pre_load
    def slugify_name(self, in_data, **kwargs):
        in_data['slug'] = in_data['slug'].lower().strip().replace(' ', '-')
        return in_data

schema = UserSchema()
result = schema.load({'name': 'Steve', 'slug': 'Steve Loria '})
result['slug']  # => 'steve-loria'

You can see detailed docs here: https://marshmallow.readthedocs.io/en/latest/extending.html#pre-processing-and-post-processing-methods

azzamsa
  • 1,805
  • 2
  • 20
  • 28
prmtl
  • 421
  • 5
  • 10
1

You can use the following custom field class (as composition):

from marshmallow import fields


class Trim(fields.Field):
    def __init__(self, inner, *args, **kwargs):
        self.inner = inner
        super().__init__(*args, **kwargs)

    def _bind_to_schema(self, field_name, parent):
        super()._bind_to_schema(field_name, parent)
        self.inner._bind_to_schema(field_name, parent)

    def _deserialize(self, value, *args, **kwargs):
        value = value.strip()
        return self.inner._deserialize(value, *args, **kwargs)

    def _serialize(self, *args, **kwargs):
        return self.inner._serialize(*args, **kwargs)

Usage example:

from marshmallow import Schema, fields

class SomeSchema(Schema):
    name = Trim(fields.String(), validate=validate.Length(max=100))
    email = Trim(fields.Email(), required=True)

Idea from here

Konstantin Smolyanin
  • 17,579
  • 12
  • 56
  • 56