Python 现代开发学习笔记

(七)把外部输入校验成业务数据

1. 注解不会自动检查一次网络输入

第三章的类型注解帮助阅读和工具分析,第四章的数据类帮助组织字段;它们不会在每次构造时自动执行所有输入规则:

# 项目文件:demos/annotations_validation.py
# 注解和dataclass不阻止错误类型进入;显式校验把错误定位到具体字段。
from webbook.http import Problem
from webbook.validation import BookDraft, validate_book

wrong = BookDraft(12, "false", "基础")
print("仍然构造", wrong.title, type(wrong.finished).__name__)
print("字符串真假", bool("false"))
try:
    validate_book({"title": 12, "finished": "false", "tags": "基础"})
except Problem as error:
    print("服务器校验", error.status, sorted(error.fields))
print(
    "校验后",
    validate_book(
        {"title": " Python Web ", "finished": False, "tags": ["网络", "网络"]}
    ),
)

第一行仍然构造出了 title 为 12、finished 为字符串的对象。bool("false") 也是 True,因为它是非空字符串,不能用它把 JSON 中错误的文本状态转成 False。

浏览器的 required、maxlength 能在页面上及时提示,但 HTTPX 或另一份页面也能直接发请求。服务器因此要自己执行字段检查。

2. 让错误对应到具体字段

# 项目文件:web_project/src/webbook/validation.py
# dataclass保存已核对的数据,真正的输入检查由函数执行,不依赖注解自动发生。
from dataclasses import dataclass

from .http import Problem, one_value


@dataclass
class BookDraft:
    title: str
    finished: bool
    tags: list[str]


def validate_book(raw):
    errors = {}
    title, finished, tags = (
        raw.get("title"),
        raw.get("finished", False),
        raw.get("tags", []),
    )
    if not isinstance(title, str) or not 1 <= len(title.strip()) <= 100:
        errors["title"] = "书名应为1至100个字符"
    if type(finished) is not bool:
        errors["finished"] = "已读状态应为布尔值"
    if (
        not isinstance(tags, list)
        or len(tags) > 10
        or any(
            not isinstance(tag, str) or not 1 <= len(tag.strip()) <= 30 for tag in tags
        )
    ):
        errors["tags"] = "标签应为至多10项的字符串数组,每项1至30个字符"
    if errors:
        raise Problem(422, "书籍字段需要修改", errors)
    return BookDraft(
        title.strip(), finished, list(dict.fromkeys(tag.strip() for tag in tags))
    )

先逐项收集错误,核对通过后才返回 BookDraft。书名与标签两端的空白被移除,重复标签保留首次出现的一项。finished 使用明确的 bool 类型,整数 1 与文本“false”都不会被当作合法 JSON 布尔值。

错误示例返回 422,fields 中分别包含 title、finished、tags,页面可以用它们给对应输入显示说明。下一章的 Pydantic 会用模型字段来组织运行时校验,仍然需要区分类型转换、字段规则与业务冲突。

数据类先能保存错误字段,运行时校验逐项收集问题,全部通过后才产生书籍草稿

笔记正文与全部题解 · Ctrl / ⌘ K