第 4 章 Field 字段约束与默认值
上一章用类型注解说明了字段是什么。可到了真实业务里,title: str 还不够:标题可能太短,阅读量不能是负数,有些字段不传时还要给个合适的值。
比如这份文章模型,除了类型,还需要这些规则:
title长度在 2 到 50 个字符之间,content至少 10 个字符。views不能小于 0,也不能超过 1,000,000。is_published默认是False,tags默认是空列表。summary可以是None,不传时也默认用None,并带上字段说明。
这章先用 Field 处理这些常见需求,不展开参数大全和自定义校验器。
本章学习目标
字段有了类型,还常常需要更具体的规则。这章会用 Field(default=...) 给字段设默认值,用 min_length、max_length 限制字符串或列表长度,用 ge、le 限制数字范围。写完规则后,也要能读懂相应的报错,知道 description 起什么作用。
Field 规则与默认值
我们继续用文章数据。下面这张图把上一章的字段类型和本章要加的规则放在一起:
title -> 字符串,长度 2 到 50
content -> 字符串,最少 10 个字符
views -> 整数,默认 0,范围 0 到 1,000,000
is_published -> 布尔值,默认 False
tags -> 字符串列表,默认空列表,最多 5 个
summary -> 可空字符串,默认 None,最多 100 个字符类型注解告诉 Pydantic 字段是什么类型;Field 可以再补上默认值、范围、长度或说明。
每个完整代码块都可以复制到本地 .code/main.py。切换示例时覆盖这个文件,然后在 .code 目录运行 uv run python main.py。
用 Field 设置默认值
Field 是 Pydantic 提供的字段辅助函数。像这样给标题加上长度限制:
title: str = Field(min_length=2, max_length=50)title 仍然是字符串,但现在至少要有 2 个字符,最多 50 个。如果只写 title: str,就没有这两条长度规则。
再看阅读量:
views: int = Field(default=0, ge=0, description="阅读量")views 仍要求整数;字段没传时用 0,传入的值不能小于 0,description 则说明这个字段表示什么。
默认值处理流程
模型收到输入后,会先看字段是否提供。没提供时,有默认值就使用它,没有默认值就记录缺失错误;提供了值,则继续做类型转换和 Field 规则校验:
这张图是帮助理解的简化流程,不是底层源码顺序。Pydantic 默认不会校验字段的默认值,所以默认值本身也要符合字段类型和规则。需要校验默认值时,可以启用 validate_default;这里先不展开配置方式。
先从两个简单默认值开始:不传 views 时用 0,不传 is_published 时用 False。
from pydantic import BaseModel, Field
class ArticleCreate(BaseModel):
title: str
content: str
views: int = Field(default=0)
is_published: bool = Field(default=False)
data = {
"title": "Pydantic Field 入门",
"content": "这是一篇介绍 Field 的文章",
}
article = ArticleCreate.model_validate(data)
print(article.title)
print(article.content)
print(article.views)
print(article.is_published)运行:
uv run python main.py可能看到类似输出:
Pydantic Field 入门
这是一篇介绍 Field 的文章
0
False对应的字段声明是:
views: int = Field(default=0)
is_published: bool = Field(default=False)没传这些字段时,模型对象里会使用默认值。title 和 content 没设默认值,仍然要在输入中提供。
长度与数值约束
常用规则速查
| 规则 | 示例 | 含义 |
|---|---|---|
| 默认值 | Field(default=0) | 字段缺失时使用默认值 |
| 字符串最小长度 | Field(min_length=2) | 字符串不能太短 |
| 字符串最大长度 | Field(max_length=50) | 字符串不能太长 |
| 数字大于等于 | Field(ge=0) | 数字必须大于等于 0 |
| 数字小于等于 | Field(le=1_000_000) | 数字必须小于等于 1,000,000 |
| 字段说明 | Field(description="文章标题") | 给字段补充说明 |
| 列表默认值 | Field(default_factory=list) | 字段缺失时生成新的空列表 |
接下来给文章标题、正文和阅读量加限制:标题长度在 2 到 50 之间,正文至少 10 个字符,阅读量不能超出 0 到 1,000,000。
from pydantic import BaseModel, Field, ValidationError
class ArticleCreate(BaseModel):
title: str = Field(min_length=2, max_length=50)
content: str = Field(min_length=10)
views: int = Field(default=0, ge=0, le=1_000_000)
is_published: bool = Field(default=False)
data = {
"title": "Pydantic Field 入门",
"content": "这是一篇介绍 Field 字段规则的文章",
"views": 100,
}
article = ArticleCreate.model_validate(data)
print(article.title)
print(article.content)
print(article.views)
print(article.is_published)
too_many_views = {**data, "views": 1_000_001}
try:
ArticleCreate.model_validate(too_many_views)
except ValidationError as e:
print("阅读量超出上限:")
print(e)运行:
uv run python main.py先看到通过校验的数据,再看到阅读量 1_000_001 超出上限的错误。完整报错还会带有其他信息,这里先看字段和核心原因:
Pydantic Field 入门
这是一篇介绍 Field 字段规则的文章
100
False
阅读量超出上限:
1 validation error for ArticleCreate
views
Input should be less than or equal to 1000000限制写在字段声明里:
title: str = Field(min_length=2, max_length=50)
content: str = Field(min_length=10)
views: int = Field(default=0, ge=0, le=1_000_000)min_length 和 max_length 管长度,ge 和 le 管数字范围。ge 是 greater than or equal,表示“大于等于”;le 是 less than or equal,表示“小于等于”。所以 ge=0 不允许负数,le=1_000_000 则给阅读量设了上限。
列表默认值、可空字段与字段说明
数字、字符串、布尔值和 None 这样的普通默认值可以直接写成 Field(default=...)。列表是可变对象,使用 default_factory=list 可以在每个模型对象创建时得到一份新的列表:
views: int = Field(default=0)
tags: list[str] = Field(default_factory=list)description 用来说明字段含义,不会增加校验规则:
title: str = Field(description="文章标题")真正负责校验的仍是 min_length、max_length、ge、le 等参数。
现在让 tags 缺失时默认为空列表、最多放 5 个标签;summary 缺失时使用 None,并补上字段说明。
from pydantic import BaseModel, Field, ValidationError
class ArticleCreate(BaseModel):
title: str = Field(min_length=2, max_length=50, description="文章标题")
content: str = Field(min_length=10, description="文章内容")
views: int = Field(default=0, ge=0, le=1_000_000, description="阅读量")
is_published: bool = Field(default=False, description="是否发布")
tags: list[str] = Field(default_factory=list, max_length=5, description="文章标签")
summary: str | None = Field(default=None, max_length=100, description="文章简介")
bad_data = {
"title": "A",
"content": "太短",
"views": -1,
"tags": ["Python", "Pydantic", "数据校验", "字段规则", "入门", "超出数量"],
}
try:
article = ArticleCreate.model_validate(bad_data)
print(article)
except ValidationError as e:
print("数据校验失败")
print(e)运行:
uv run python main.py这份输入里标题太短、正文太短、阅读量为负数,标签数量也超了。Pydantic 会把这些错误一起列出来;下面只展示错误字段和主要原因:
数据校验失败
4 validation errors for ArticleCreate
title
String should have at least 2 characters
content
String should have at least 10 characters
views
Input should be greater than or equal to 0
tags
List should have at most 5 items after validation, not 6tags 的规则是:
tags: list[str] = Field(default_factory=list, max_length=5, description="文章标签")字段缺失时,Pydantic 会生成一个新的空列表;标签数量不能超过 5。summary 的声明则同时表达“值可以是字符串或 None”以及“缺失时默认用 None”:
summary: str | None = Field(default=None, max_length=100, description="文章简介")可空类型和默认值有关联,但含义不同:前者说明允许哪些值,后者说明输入缺失时怎么办。
默认值的填充结果
刚才看的是错误数据,这次用正确数据观察默认值实际落到模型对象里的结果。仍然只传 title 和 content:
from pydantic import BaseModel, Field
class ArticleCreate(BaseModel):
title: str = Field(min_length=2, max_length=50, description="文章标题")
content: str = Field(min_length=10, description="文章内容")
views: int = Field(default=0, ge=0, le=1_000_000, description="阅读量")
is_published: bool = Field(default=False, description="是否发布")
tags: list[str] = Field(default_factory=list, max_length=5, description="文章标签")
summary: str | None = Field(default=None, max_length=100, description="文章简介")
data = {
"title": "Pydantic Field 入门",
"content": "这是一篇介绍 Field 字段规则的文章",
}
article = ArticleCreate.model_validate(data)
print("文章标题:", article.title)
print("文章内容:", article.content)
print("阅读量:", article.views)
print("是否发布:", article.is_published)
print("文章标签:", article.tags)
print("文章简介:", article.summary)
print("标题字段说明:", ArticleCreate.model_fields["title"].description)
article.tags.append("Python")
another_article = ArticleCreate.model_validate(data)
print("第一篇文章新增标签:", article.tags)
print("第二篇文章标签:", another_article.tags)运行:
uv run python main.py可能看到类似输出:
文章标题: Pydantic Field 入门
文章内容: 这是一篇介绍 Field 的文章
阅读量: 0
是否发布: False
文章标签: []
文章简介: None
标题字段说明: 文章标题
第一篇文章新增标签: ['Python']
第二篇文章标签: []虽然输入里只有 title 和 content,views、is_published、tags 和 summary 也都出现在模型对象中,因为它们设置了默认值。ArticleCreate.model_fields["title"].description 能读到标题说明;它只做说明,不参与校验。
代码还给第一篇文章的 tags 加入了 "Python",第二篇文章的标签仍是空列表。这能直接看出 default_factory=list 为不同模型对象创建了独立列表。
文章字段规则校验
最后把默认值和规则放到一个完整案例里,分别提交正确和错误的数据:
from pydantic import BaseModel, Field, ValidationError
class ArticleCreate(BaseModel):
title: str = Field(min_length=2, max_length=50, description="文章标题")
content: str = Field(min_length=10, description="文章内容")
views: int = Field(default=0, ge=0, le=1_000_000, description="阅读量")
is_published: bool = Field(default=False, description="是否发布")
tags: list[str] = Field(default_factory=list, max_length=5, description="文章标签")
summary: str | None = Field(default=None, max_length=100, description="文章简介")
data = {
"title": "Pydantic Field 入门",
"content": "这是一篇介绍 Field 字段规则的文章",
"tags": ["Python", "Pydantic"],
"summary": "本章学习 Field 的常用字段规则",
}
try:
article = ArticleCreate.model_validate(data)
print("文章标题:", article.title)
print("阅读量:", article.views)
print("是否发布:", article.is_published)
print("文章标签:", article.tags)
print("文章简介:", article.summary)
except ValidationError as e:
print("正确数据校验失败")
print(e)
bad_data = {
"title": "A",
"content": "太短",
"views": -1,
"tags": ["Python", "Pydantic", "数据校验", "字段规则", "入门", "超出数量"],
"summary": "这是一段非常长的文章简介" * 20,
}
try:
bad_article = ArticleCreate.model_validate(bad_data)
print(bad_article)
except ValidationError as e:
print("错误数据校验失败")
print(e)运行:
uv run python main.py先看正确数据怎样得到带默认值的模型对象,再看错误数据怎样在 model_validate() 阶段被拦下。错误数据同时包含过短的标题和正文、负数阅读量、过多标签,以及超长简介。
本章小结
Field 可以补默认值、长度和数值范围,也能给字段写说明。普通默认值用 default;列表要生成新默认值时,用 default_factory=list。min_length、max_length 管长度,ge、le 管数值。description 方便人读,不参与校验。