- 字段高级配置 数据校验,复用Pydantic能力)
这里写目录标题前言一、阶段学习目标二、Field 双端高级配置数据库约束 Pydantic校验2.1 Field 参数两大分类2.2 default 与 default_factory 核心区别高频踩坑点2.3 高级数据库约束联合索引、自定义列类型三、复用Pydantic专用校验类型开箱即用3.1 邮箱、链接、UUID、IP3.2 Enum 枚举状态约束角色、订单状态四、标准分层DTO模型企业开发规范隔离数据库与接口4.1 四层分层设计思路4.2 完整用户分层实战代码4.3 DTO转换与脱敏示例五、复用Pydantic自定义校验 field_validator5.1 用户名自动去空格、小写清洗5.2 密码复杂度自定义校验大写小写数字5.3 手机号正则校验六、序列化精细化控制敏感字段隐藏6.1 Field(excludeTrue) 永久不序列化6.2 model_dump 动态过滤参数七、阶段综合完整可运行案例八、阶段核心总结半天必掌握九、新手高频避坑指南前言上一篇我们学习了SQLModel基础概念、Engine、Session与单表CRUD掌握了最基础的表定义与数据库操作。但真实业务里单纯基础字段完全无法满足需求字符串长度、数字区间、邮箱/URL格式需要强校验枚举状态、联合索引、UUID主键、自动时间戳需要高级字段配置新增、更新、接口返回需要分层模型隔离敏感字段自定义密码、手机号等复杂业务校验逻辑。SQLModel底层完全融合Pydantic v2所有Pydantic校验能力可直接复用不用两套模型重复写校验规则。一、阶段学习目标精通Field双端配置数据库列参数 Pydantic校验参数掌握默认值区分default静态值 /default_factory动态生成时间、UUID、列表学会高级数据库约束联合索引、自定义字段类型、非空/唯一复用Pydantic专用类型EmailStr、HttpUrl、UUID、枚举Enum标准分层DTO设计Base基础模型 / Create创建模型 / Update更新模型 / Public返回模型在SQLModel中使用field_validator自定义业务校验掌握序列化脱敏、隐藏敏感字段密码不返回前端。二、Field 双端高级配置数据库约束 Pydantic校验2.1 Field 参数两大分类SQLModel的Field一套参数同时作用两层SQL层参数控制数据库表结构primary_key、index、unique、nullable、sa_column、sa_typePydantic校验参数入参自动校验和Pydantic完全通用min_length、max_length、gt、ge、lt、le、pattern、description2.2 default 与 default_factory 核心区别高频踩坑点defaultxxx静态常量模块加载时只计算一次禁止列表、字典、时间、UUIDdefault_factory函数每次实例化动态执行可变类型、动态值必用。示例fromsqlmodelimportSQLModel,FieldfromdatetimeimportdatetimeimportuuidclassUser(SQLModel,tableTrue):id:uuid.UUIDField(default_factoryuuid.uuid4,primary_key,descriptionUUID主键)# 静态默认固定布尔值is_active:boolField(defaultTrue,nullableFalse)# 动态生成创建时间每次新建自动赋值当前UTC时间create_time:datetimeField(default_factorydatetime.utcnow)# 错误写法defaultdatetime.utcnow() 全局只会生成同一个时间2.3 高级数据库约束联合索引、自定义列类型单字段索引直接indexTrue多字段联合索引使用__table_args__定义索引元组fromsqlmodelimportSQLModel,FieldfromsqlalchemyimportIndexclassUser(SQLModel,tableTrue):__tablename__sys_user# 联合索引用户名邮箱联合唯一__table_args__(Index(idx_username_email,username,email,uniqueTrue),)id:int|NoneField(defaultNone,primary_keyTrue)username:strField(max_length32,nullableFalse)email:strField(max_length128,nullableFalse)age:int|NoneField(defaultNone,ge0,le120)自定义数据库字段类型长文本、大整数fromsqlalchemyimportText,BigIntegerclassArticle(SQLModel,tableTrue):id:int|NoneField(defaultNone,primary_key,sa_typeBigInteger)content:strField(sa_columnText(),description文章长文本内容)三、复用Pydantic专用校验类型开箱即用SQLModel可直接导入使用Pydantic全部专用校验类型无需手写正则自动拦截非法格式。3.1 邮箱、链接、UUID、IPfromsqlmodelimportSQLModel,FieldfrompydanticimportEmailStr,HttpUrl,UUID4,IPvAnyAddressimportuuidclassUser(SQLModel,tableTrue):id:UUID4Field(default_factoryuuid.uuid4,primary_keyTrue)# 自动校验合法邮箱email:EmailStrField(uniqueTrue,indexTrue,max_length128)# 头像合法URL校验avatar:HttpUrl|NoneField(defaultNone)# 登录IP自动校验IPv4/IPv6login_ip:IPvAnyAddress|NoneField(defaultNone)3.2 Enum 枚举状态约束角色、订单状态使用str枚举配合SQLEnum数据库原生枚举约束同时Pydantic自动校验传值范围fromenumimportEnumfromsqlmodelimportSQLModel,FieldfromsqlalchemyimportSQLEnumclassUserRole(str,Enum):ADMINadminUSERuserGUESTguestclassUser(SQLModel,tableTrue):id:int|NoneField(defaultNone,primary_keyTrue)username:strField(min_length3,max_length16)# 数据库枚举 Pydantic值范围校验role:UserRoleField(defaultUserRole.GUEST,sa_columnSQLEnum(UserRole,nameuser_role_enum))测试非法值会直接抛出ValidationError无需手动if判断。四、标准分层DTO模型企业开发规范隔离数据库与接口4.1 四层分层设计思路XxxBase基础公共模型存放所有通用字段统一校验规则XxxCreate新增接口入参模型不含主键、自动生成字段XxxUpdate更新接口模型所有字段全部可选支持局部修改XxxPublic接口返回模型剔除密码等敏感字段仅对外暴露安全数据Xxx(tableTrue)数据库实体继承Base增加主键、数据库专属字段。4.2 完整用户分层实战代码fromsqlmodelimportSQLModel,FieldfrompydanticimportEmailStrfromtypingimportOptionalimportuuid# 1. 基础公共模型统一校验规则classUserBase(SQLModel):username:strField(min_length3,max_length16,description用户名3-16位)email:EmailStrField(max_length128)age:Optional[int]Field(defaultNone,ge0,le120)# 2. 创建入参模型继承Base新增密码字段classUserCreate(UserBase):password:strField(min_length8,max_length20,description密码8-20位)# 3. 更新入参模型全部字段可选支持局部更新classUserUpdate(SQLModel):username:Optional[str]Field(None,min_length3,max_length16)email:Optional[EmailStr]Noneage:Optional[int]Field(None,ge0,le120)# 4. 返回脱敏模型隐藏密码携带主键classUserPublic(UserBase):id:uuid.UUID# 5. 数据库实体继承Base映射数据表classUser(UserBase,SQLModel,tableTrue):id:uuid.UUIDField(default_factoryuuid.uuid4,primary_keyTrue)password:strField(max_length100,description加密密码不对外返回)create_time:strField(default_factorylambda:str(uuid.uuid4()))4.3 DTO转换与脱敏示例# 数据库实体转返回DTO自动剔除password敏感字段db_userUser(usernametest,emailtestqq.com,passwordAbc123456)respUserPublic.model_validate(db_user)print(resp.model_dump())# 输出无password安全返回前端五、复用Pydantic自定义校验 field_validatorSQLModel完全兼容Pydantic v2校验装饰器单字段清洗、复杂业务规则直接复用数据库实体与DTO模型均可使用。5.1 用户名自动去空格、小写清洗fromsqlmodelimportSQLModel,Fieldfrompydanticimportfield_validatorclassUserCreate(SQLModel):username:strField(min_length3,max_length16)email:strfield_validator(username,modebefore)defclean_username(cls,v):ifisinstance(v,str):returnv.strip().lower()returnv5.2 密码复杂度自定义校验大写小写数字importrefromsqlmodelimportSQLModel,Fieldfrompydanticimportfield_validator,ValidationErrorclassUserCreate(SQLModel):password:strField(min_length8,max_length20)field_validator(password,modeafter)defcheck_pwd_rule(cls,v):ifnotre.search(r[A-Z],v):raiseValueError(密码必须包含大写字母)ifnotre.search(r[a-z],v):raiseValueError(密码必须包含小写字母)ifnotre.search(r\d,v):raiseValueError(密码必须包含数字)returnv# 测试校验try:UserCreate(password123456)exceptValidationErrorase:print(e.errors()[0][msg])5.3 手机号正则校验fromsqlmodelimportSQLModel,Fieldfrompydanticimportfield_validatorimportreclassUserCreate(SQLModel):phone:strfield_validator(phone)defcheck_phone(cls,v):ifnotre.match(r^1[3-9]\d{9}$,v):raiseValueError(请输入合法11位手机号)returnv六、序列化精细化控制敏感字段隐藏6.1 Field(excludeTrue) 永久不序列化数据库密码字段无论怎么转字典/JSON永远隐藏classUser(SQLModel,tableTrue):id:int|NoneField(defaultNone,primary_keyTrue)username:str# 序列化永久排除密码password:strField(excludeTrue,max_length100)userUser(usernameadmin,password123Abc666)print(user.model_dump())# 输出不含password6.2 model_dump 动态过滤参数userUser(...)# 过滤所有None空值user.model_dump(exclude_noneTrue)# 仅保留用户传入字段过滤默认值user.model_dump(exclude_unsetTrue)# 临时手动排除指定字段user.model_dump(exclude{password})七、阶段综合完整可运行案例整合高级字段、枚举、分层DTO、自定义校验、脱敏全部知识点fromsqlmodelimportSQLModel,Field,create_engine,SessionfrompydanticimportEmailStr,field_validator,ValidationErrorfromenumimportEnumfromsqlalchemyimportSQLEnumimportre# 1. 枚举定义classUserRole(str,Enum):ADMINadminUSERuser# 2. 基础模型classUserBase(SQLModel):username:strField(min_length3,max_length16)email:EmailStr# 3. 创建模型带密码校验classUserCreate(UserBase):password:strField(min_length8)role:UserRoleField(defaultUserRole.USER)field_validator(password)defpwd_check(cls,v):ifnotre.search(r[A-Za-z0-9],v):raiseValueError(密码需包含字母数字)returnv# 4. 返回脱敏模型classUserPublic(UserBase):id:introle:UserRole# 5. 数据库实体classUser(UserBase,SQLModel,tableTrue):id:int|NoneField(defaultNone,primary_keyTrue)password:strField(excludeTrue)role:UserRoleField(sa_columnSQLEnum(UserRole))# 数据库初始化enginecreate_engine(sqlite:///stage2.db,echoFalse)SQLModel.metadata.create_all(bindengine)# 新增测试if__name____main__:try:create_dataUserCreate(username Admin666 ,emailadmintest.com,passwordAbc123456,roleadmin)withSession(engine)assession:db_userUser.model_validate(create_data)session.add(db_user)session.commit()session.refresh(db_user)# 脱敏返回respUserPublic.model_validate(db_user)print(接口返回数据,resp.model_dump())exceptValidationErrorase:print(参数校验失败,e.errors())八、阶段核心总结半天必掌握Field同时承载数据库列配置与Pydantic数据校验一套代码两用动态默认值统一使用default_factory避免可变类型全局复用问题联合索引通过__table_args__定义枚举搭配SQLEnum实现数据库层约束直接复用Pydantic内置EmailStr/HttpUrl/UUID等专用校验类型四层分层DTOBase/Create/Update/Public是前后端项目标准规范隔离敏感字段SQLModel原生支持field_validator可复用全部Pydantic自定义校验逻辑Field(excludeTrue)永久隐藏密码等敏感数据接口序列化自动脱敏。九、新手高频避坑指南❌ 可变类型list/datetime/uuid使用default所有实例共享同一个值❌ 数据库实体直接返回前端泄露password、密钥等敏感字段❌ 更新模型复用Base基类字段不带Optional导致必须传全量参数❌ 不用枚举直接用字符串存储角色/状态缺少入参校验✅ 所有接口分层定义DTO数据库实体仅用于数据库操作✅ 复杂格式校验密码、手机号统一使用field_validator减少业务if判断。