Flask API请求体验证:允许useCaseId字段支持字符串与字典类型
Got it, let's tweak your Marshmallow schema so useCaseId accepts both strings and dictionaries—here are two solid ways to do it:
Method 1: Custom Validator with fields.Raw (Works for all Marshmallow versions)
This approach uses a custom validation function to check that the value is either a non-empty string or a dictionary, and works with any Marshmallow version.
from marshmallow import Schema, fields, validate, ValidationError # This function validates the request body def validatefilterdata(data): # Custom validator to enforce useCaseId is either string (min length 1) or dict def validate_use_case_id(value): if isinstance(value, str): if len(value) < 1: raise ValidationError("useCaseId string must be at least 1 character long") elif not isinstance(value, dict): raise ValidationError("useCaseId must be either a string or a dictionary") class FilterDataSchema(Schema): masterBotId = fields.Str(validate=validate.Length(min=1), required=False) # Updated field to use Raw + custom validator useCaseId = fields.Raw(validate=validate_use_case_id, required=False) month = fields.Str(required=False) dateRange = fields.Dict(required=False) filetdata_schema = FilterDataSchema(strict=True) validation_result = filetdata_schema.load(data) return validation_result.errors
How it works:
fields.Rawis the base class for all Marshmallow fields, so it doesn't enforce a specific data type by default.- Our custom
validate_use_case_idfunction checks if the value is a string (and validates its length) OR a dictionary. If neither, it throws a clear validation error.
Method 2: Use fields.Union (Marshmallow 3.0+ only)
If you're running Marshmallow 3.0 or newer, the Union field is a cleaner, more idiomatic solution. It lets you define multiple acceptable field types, and Marshmallow will try each one until it finds a match.
from marshmallow import Schema, fields, validate, ValidationError def validatefilterdata(data): class FilterDataSchema(Schema): masterBotId = fields.Str(validate=validate.Length(min=1), required=False) # Union field accepts either a non-empty string or a dictionary useCaseId = fields.Union([ fields.Str(validate=validate.Length(min=1)), fields.Dict() ], required=False) month = fields.Str(required=False) dateRange = fields.Dict(required=False) filetdata_schema = FilterDataSchema(strict=True) validation_result = filetdata_schema.load(data) return validation_result.errors
How it works:
fields.Uniontakes a list of field types. When deserializing, it will attempt to validate the value against each field in order.- If the value is a string, it passes through the
Strfield's length validation. If it's a dictionary, it passes through theDictfield. Any other type will trigger a validation error.
Pro tip: If you need to add more context to the error messages for Union, you can pass an error_messages parameter to the Union field to make errors clearer for API consumers.
内容的提问来源于stack exchange,提问作者Tony Mathew

