Search code examples
pythonflaskflask-sqlalchemymarshmallow

flask-marshmallow validation on field data not working


Hi I made my dto something like this

class MyRequestDto(ma.Schema):
    @pre_load
    def wrap_data(self, in_data, **kwargs):
        return {"rooms": in_data}


    rooms = ma.Dict(ma.String, ma.Dict(ma.Integer, ma.String))

and I want to send request something like this :

{   
    "1faf8f07-2977-180e-7bc2-b5adf8badasda": {"student_id":11210687,"room_id":"100"}
}

but getting error like this

{
    "rooms": {
        "1faf8f07-2977-180e-7bc2-b5adf8badasda": {
            "value": {
                "student_id": {
                    "key": [
                        "Not a valid integer."
                    ]
                },
                "room_id": {
                    "key": [
                        "Not a valid integer."
                    ]
                }
            }
        }
    }
}

What I can do to pass data correctly in the required format?


Solution

  • Integer type supports cast.

    From the documentation:

    class marshmallow.fields.Integer(*, strict: bool = False, **kwargs)[source]
        An integer field.
        Parameters
                strict – If True, only integer types are valid. Otherwise, any value castable to int is valid.
                kwargs – The same keyword arguments that Number receives.
    

    So try:

    class MyRequestDto(Schema):
        @pre_load
        def wrap_data(self, in_data, **kwargs):
            return {"rooms": in_data}
    
        rooms = Dict(String, Dict(String, Integer))
    

    It will automatically handle the str for room_id.

    If you want to keep room_id as str then you need to define a Custom Field.

    Example:

    class CustomField(Field):
        def _serialize(self, value, attr, obj, **kwargs):
            if isinstance(value, (str, int)):
                return value
            raise ValidationError("Value is not int or str")
    
        def _deserialize(self, value, attr, data, **kwargs):
            if isinstance(value, (str, int)):
                return value
            raise ValidationError("Value is not int or str")
    
    
    class MyRequestDto(Schema):
        @pre_load
        def wrap_data(self, in_data, **kwargs):
            return {"rooms": in_data}
    
        rooms = Dict(String, Dict(String, CustomField))