Search code examples
pythonpython-3.xflaskmarshmallow

flask+marshmallow set default value if value is invalid


I am using flask+marshmallow to validate user payload. When any GET/POST request received, I am coping request.args or request.form to request.req_data. Below is the code.

class BaseMethodView(MethodView):

    view_template = None


    def __init__(self, *args, **kwargs):
        assert issubclass(self.validator_class, core_validator.BaseValidator), (
            "Invalid validator found."
        )
        assert issubclass(self.service_class, BaseService), "Invalid Service found."
        assert self.view_template, "Template not defined"
        super().__init__(*args, **kwargs)

    def validate(self, payload, *args, **kwargs):
        self.validator_class().validate(payload)

    def process_request(self):
        search_data = self.service_class(request).execute()
        return render_template(self.view_template, data=search_data)

    def get(self):
        request.req_data = request.args.copy()
        self.validate(request.req_data)
        return self.process_request()

    def post(self):
        request.req_data = request.form.copy()
        self.validate(request.req_data)
        return self.process_request()

Requirement- In validator I am validating the fields. And if some fields value is not valid then I want to set to the default value rather than raising any Exception. How to it?

class CategoryField(fields.String):
    def _deserialize(self, value, attr, data, **kwargs):
        if value not in ("choice1", "choice2", "choice3"):
            return "choice1"
        super()._deserialize(value, attr, data)


class SearchValidator(core_validator.BaseValidator):
    query = fields.Str(required=True)
    cat = CategoryField()

    class Meta:
        strict = True
        skip_on_field_errors=False
        # INCLUDE: pass those keys/values as is, with no validation performed
        unknown = INCLUDE

If not marshmallow then can you suggest some other better library? I am also experimeting with marshmallow.decorators.post_dump but no luck.


Solution

  • You must be calling Schema().validate() method. Instead call Schema().load(request.args) method which always call method decorated with @post_load. also Don't forget to set postprocess = True in Metas class of schema.

    class SearchValidator(core_validator.BaseValidator):
        query = fields.Str(required=True)
        cat = CategoryField()
    
        class Meta:
            strict = True
            skip_on_field_errors=False
            # INCLUDE: pass those keys/values as is, with no validation performed
            unknown = INCLUDE
            postprocess = True
    

    while calling, use SearchValidator().load(payload) instead of SearchValidator().validate().