title: Pydantic字段级校验:解锁@validator的12种应用
date: 2025/3/23
updated: 2025/3/23
author: cmdragon

excerpt:
Pydantic校验系统支持通过pre验证器实现原始数据预处理,在类型转换前完成字符清洗等操作。格式验证涵盖正则表达式匹配与枚举值约束,确保护照编号等字段符合规范。动态校验机制处理跨字段依赖关系及环境感知验证,根据运行时条件调整校验规则。安全校验模块防御SQL注入与XSS攻击,采用字符过滤和HTML转义策略。高级转换功能实现地址标准化、敏感信息加密等数据处理,企业级实践包含分布式ID验证与金融精度控制。校验错误处理需关注类型一致性及验证顺序,遵循"早失败"原则构建模块化校验规则库,推荐使用参数化查询等最佳安全实践。

categories:

  • 后端开发
  • FastAPI

tags:

  • Pydantic字段校验
  • @validator高级应用
  • 数据验证模式
  • 防御式编程
  • 校验器组合
  • 动态依赖验证
  • 企业级数据清洗

image

image

扫描二维码关注或者微信搜一搜:编程智域 前端至全栈交流与成长

探索数千个预构建的 AI 应用,开启你的下一个伟大创意


第一章:基础校验模式

1.1 类型强制转换

from pydantic import BaseModel, validator


class CurrencyConverter(BaseModel):
    amount: str

    @validator("amount", pre=True)
    def string_to_float(cls, v):
        return float(v.strip("$"))


# 自动转换 "$100.5" → 100.5
print(CurrencyConverter(amount="$100.5").amount)  

pre验证器特性

  • 在类型转换前执行
  • 支持原始数据清洗
  • 可处理非结构化输入

第二章:格式验证

2.1 正则表达式验证

import re


class IdentityForm(BaseModel):
    passport: str

    @validator("passport")
    def validate_passport(cls, v):
        if not re.match(r"^[A-PR-WY][1-9]\d\s?\d{4}[A-Z]$", v):
            raise ValueError("护照号码格式错误")
        return v.upper().replace(" ", "")

2.2 枚举值约束

from enum import Enum


class Department(Enum):
    HR = 1
    IT = 2


class Employee(BaseModel):
    dept: int

    @validator("dept")
    def check_department(cls, v):
        return Department(v).name  # 自动转换数字为枚举名称

第三章:动态校验

3.1 跨字段依赖验证

class OrderForm(BaseModel):
    product_type: str
    weight: float

    @validator("weight")
    def check_weight(cls, v, values):
        if values.get("product_type") == "fragile" and v > 10:
            raise ValueError("易碎品不得超过10kg")
        return v

3.2 环境感知校验

import os


class EnvAwareValidator(BaseModel):
    api_key: str

    @validator("api_key")
    def check_key_format(cls, v):
        env = os.getenv("APP_ENV", "dev")
        if env == "prod" and len(v) < 32:
            raise ValueError("生产环境密钥强度不足")
        return v

第四章:安全校验

4.1 SQL注入防御

class QuerySafe(BaseModel):
    search_term: str

    @validator("search_term")
    def sanitize_input(cls, v):
        forbidden = ["'", ";", "--", "/*"]
        if any(c in v for c in forbidden):
            raise ValueError("检测到危险字符")
        return v.replace("%", "\\%")

4.2 XSS攻击过滤

from html import escape


class CommentForm(BaseModel):
    content: str

    @validator("content")
    def sanitize_html(cls, v):
        return escape(v).replace("\n", "<br>")

第五章:高级转换

5.1 数据归一化

class AddressNormalizer(BaseModel):
    street: str

    @validator("street")
    def standardize_address(cls, v):
        replacements = {
            "St.": "Street",
            "Ave": "Avenue"
        }
        for k, v in replacements.items():
            v = v.replace(k, v)
        return v.title()

5.2 加密字段处理

from cryptography.fernet import Fernet


class SecureData(BaseModel):
    secret: str

    @validator("secret")
    def encrypt_value(cls, v):
        key = Fernet.generate_key()
        return Fernet(key).encrypt(v.encode())

第六章:企业级实践

6.1 分布式ID验证

import snowflake


class SnowflakeValidator(BaseModel):
    object_id: str

    @validator("object_id")
    def validate_snowflake(cls, v):
        try:
            snowflake.deconstruct(v)
            return v
        except Exception:
            raise ValueError("非法分布式ID格式")

6.2 金融精度控制

from decimal import Decimal, ROUND_HALF_UP


class FinancialModel(BaseModel):
    amount: float

    @validator("amount")
    def monetary_precision(cls, v):
        return Decimal(str(v)).quantize(
            Decimal("0.00"),
            rounding=ROUND_HALF_UP
        )

课后Quiz

Q1:pre验证器的执行时机是?
A) 类型转换后
B) 类型转换前
C) 最终验证阶段

Q2:防御SQL注入的最佳方法是?

1) 字符串替换
2) 参数化查询
3) 正则过滤

Q3:处理多字段依赖应使用?

  • [x] root_validator
  • [ ] 多个字段级校验器
  • [ ] 自定义__init__方法

错误解决方案速查表

错误信息原因分析解决方案
ValidationError: value is not a valid integer类型转换前未清洗数据添加pre=True验证器
ValueError: 检测到危险字符SQL注入防御生效使用参数化查询替代直接拼接
AssertionError: 校验顺序错误依赖字段未优先验证调整字段定义顺序
TypeError: 校验器返回类型错误验证器返回值与声明类型不符检查验证器逻辑

架构原则:字段校验应遵循"早失败"原则,在数据入口处完成所有验证。建议建立企业级校验规则库,通过装饰器模式实现校验逻辑的模块化管理。

余下文章内容请点击跳转至 个人博客页面 或者 扫码关注或者微信搜一搜:编程智域 前端至全栈交流与成长,阅读完整的文章:

往期文章归档:


风流倜傥的伤痕
79 声望23 粉丝