使用Pydantic与Annotated验证POST请求URL的问题排查
解决Pydantic URL验证与SQLAlchemy类型兼容问题
问题根源
- 用
Annotated[str, HttpUrl]时,HttpUrl只是元数据标记,Pydantic不会自动执行验证逻辑,所以像www.bad.example这种缺协议的无效URL不会触发报错。 - 直接把字段类型设为
HttpUrl,Pydantic会把输入转成pydantic_core._pydantic_core.Url对象,但SQLAlchemy不支持这个类型,写入数据库时就会抛出ProgrammingError。
两种可行解决方案
方案1:给字符串字段加验证器
用Pydantic的field_validator,给str类型的url字段套上HttpUrl的验证规则,验证通过后返回原始字符串,既保留str类型又完成校验。
代码示例:
from pydantic import BaseModel, field_validator, HttpUrl class YourAPISchema(BaseModel): url: str @field_validator('url') def check_url_valid(cls, value): # 用HttpUrl逻辑校验输入,不合法直接抛ValidationError HttpUrl(value) # 返回原始字符串,保持字段类型为str return value
方案2:用类型别名封装验证+序列化逻辑
如果多个Schema都需要这类URL验证,封装成类型别名更高效,通过BeforeValidator执行校验,PlainSerializer把结果转回字符串。
代码示例:
from pydantic import BaseModel, HttpUrl, BeforeValidator, PlainSerializer from typing import Annotated # 封装可复用的类型别名 ValidatedUrlStr = Annotated[ str, BeforeValidator(lambda val: HttpUrl(val)), # 先执行HttpUrl验证 PlainSerializer(lambda val: str(val), return_type=str) # 输出时转回字符串 ] class YourAPISchema(BaseModel): url: ValidatedUrlStr
测试验证
用Pytest测试时,无效URL会触发ValidationError,合法URL通过验证后仍为str类型,写入SQLAlchemy完全兼容。
测试用例参考:
import pytest from pydantic import ValidationError from your_module import YourAPISchema def test_invalid_url_rejected(): with pytest.raises(ValidationError): YourAPISchema(url="www.bad.example") def test_valid_url_kept_as_str(): schema_instance = YourAPISchema(url="https://good.example.com") assert isinstance(schema_instance.url, str) assert schema_instance.url == "https://good.example.com"
内容的提问来源于stack exchange,提问作者Czech Assassin
相关产品推荐
相关产品推荐

