在Pydantic中实现FilePath与stricturl联合类型的问题及解决方案咨询
解决Pydantic中Union[FilePath, stricturl]的校验冲突问题
我之前也碰到过一模一样的坑——Pydantic的Union在处理FilePath和stricturl时,不管怎么调整顺序,都会出现校验错位的问题:URL被当成文件路径校验,文件路径又被硬套URL规则。
问题根源
核心原因其实是两种类型的校验逻辑存在“误判重叠”:
FilePath的校验逻辑(尤其是旧版Pydantic)不会主动过滤带协议的URL字符串,它会把https://example.com这类字符串当成合法的路径格式(比如类Unix系统里会把https://当作相对路径前缀,Windows里会解析为UNC路径的一部分),所以会意外通过校验。- 反过来,如果把
stricturl放在Union前面,普通文件路径又会被URL校验器强制解析,自然失败。
可行解决方案:自定义校验逻辑
最可靠的做法是跳过Union的自动匹配,自己实现“先判断格式,再针对性校验”的逻辑,下面提供两种常用方式:
方法1:字段级自定义校验器
适合只在单个模型里使用的场景:
from pydantic import BaseModel, ValidationError, field_validator from pydantic.types import FilePath from pydantic.networks import stricturl class Picture(BaseModel): src: str @field_validator('src') def validate_src(cls, value): # 优先尝试URL校验(按你的需求只允许https) try: return stricturl(allowed_schemes=["https"])(value) except ValidationError: # URL校验失败,再尝试文件路径校验 try: return FilePath(value) except ValidationError: raise ValueError("src必须是有效的HTTPS URL或已存在的文件路径") # 测试示例 try: # 合法HTTPS URL valid_url_pic = Picture(src="https://www.robingruenke.com") print("URL校验通过:", valid_url_pic.src) # 合法本地文件路径(假设文件存在) valid_file_pic = Picture(src="/Users/you/pictures/test.jpg") print("文件路径校验通过:", valid_file_pic.src) # 非法输入 invalid_pic = Picture(src="invalid-content") except ValidationError as e: print("校验失败:", e)
方法2:自定义可复用类型
如果需要在多个模型里复用这个规则,可以封装成自定义Pydantic类型:
from pydantic import GetCoreSchemaHandler, ValidationError from pydantic.types import FilePath from pydantic.networks import stricturl from pydantic_core import core_schema class HTTPSUrlOrFilePath: @classmethod def __get_pydantic_core_schema__(cls, source_type, handler: GetCoreSchemaHandler) -> core_schema.CoreSchema: # 分别获取两种类型的核心校验规则 url_schema = stricturl(allowed_schemes=["https"]).__get_pydantic_core_schema__(source_type, handler) file_schema = FilePath.__get_pydantic_core_schema__(source_type, handler) def validate(value): try: return url_schema['type'](value) except ValidationError: try: return file_schema['type'](value) except ValidationError: raise ValueError("必须是有效的HTTPS URL或已存在的文件路径") return core_schema.no_info_plain_validator_function(validate) # 直接在模型中使用自定义类型 class Picture(BaseModel): src: HTTPSUrlOrFilePath
关于你的测试用例
注意你的测试用例里用的是http协议的URL,但模型里只允许https,所以当前校验失败是符合预期的。如果需要支持http,只需要把allowed_schemes改成["http", "https"]即可。
内容的提问来源于stack exchange,提问作者rgruenke
相关产品推荐
相关产品推荐

