Pydantic:
-
Pydantic 是 Fastapi 的核心依赖,用于数据校验和序列化。
-
通过使用Python类型注解定义数据结构,它负责自动完成数据校验和转换。
-
通过继承BaseModel类来定义一个Pydantic模型,字段是否必填取决于是否有默认值,没有默认值的字段为必填。
常用函数:
-
Pydantic模型序列化为字典:
item.model_dump()【item为pydantic模型实例】 -
Pydantic模型序列化为 json:
item.model_dump_json()【item为pydantic模型实例】 -
从字典创建Pydantic模型,并自动校验:
User.model_validate(user_dict)bashfrom pydantic import BaseModel, EmailStr class User(BaseModel): name: str age: int email: EmailStr # 这是 Python 字典! user_dict = { "name": "小明", "age": 20, "email": "test@qq.com" } # 字典 → 模型 + 自动校验 user = User.model_validate(user_dict) -
从 json 创建Pydantic模型,并自动校验:
User.model_validate_json(json_str)bash# 这是 JSON 字符串! json_str = ''' { "name": "小红", "age": 18, "email": "test@qq.com" } ''' # JSON字符串 → 模型 + 自动校验 user = User.model_validate_json(json_str)
-
模型配置 ------(作用:控制模型行为)
一、最常用模型配置
python
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
model_config = {
# 1. 允许从 ORM 对象读取数据(必用!)
"from_attributes": True,
# 2. 禁止额外字段(安全必开!)
"extra": "forbid",
# 3. 字符串自动去除空格(必用)
"str_strip_whitespace": True,
# 4. 支持别名(驼峰/下划线互转)
"populate_by_name": True,
# 5. 宽松类型转换(更友好)
"coerce_numbers": True,
# 6. 自定义 API 文档示例
"json_schema_extra": {
"example": {
"name": "张三",
"age": 20
}
},
# 7. 时间格式统一
"ser_json_tz": False,
# 8. 枚举使用值而不是名称
"use_enum_values": True
}
二、每个参数作用 + 为什么要用
1. from_attributes = True(最最最重要)
作用 :让模型支持从 ORM 模型(数据库对象) 直接转换
为什么企业用 :
数据库查出来的对象,一行代码转成接口返回模型
python
user = User.model_validate(db_user)
2. extra = "forbid"(安全必开)
作用 :拒绝多余字段
前端多传乱七八糟的字段 → 直接报错
为什么企业用 :
防止脏数据、防止攻击、保证接口严格规范
可选值:
forbid→ 禁止额外字段(推荐)ignore→ 忽略allow→ 允许(不推荐)
3. str_strip_whitespace = True
作用 :字符串自动去空格
" 张三 " → "张三"
为什么企业用 :
用户输入经常带空格,统一处理避免bug
4. populate_by_name = True
作用 :支持字段别名
比如:
- 模型字段:
user_id - 接收:
userId
为什么企业用 :
前端用驼峰,后端用下划线,自动兼容
5. coerce_numbers = True
作用 :自动类型转换
"18" → 18
"20.5" → 20.5
为什么企业用 :
前端传字符串数字,后端自动转 int/float,不报错
6. json_schema_extra
作用 :给 API 文档加示例
为什么企业用 :
前端看文档一目了然
7. use_enum_values = True
作用:枚举返回值,而不是枚举名称
python
# 枚举
class Status(str, Enum):
SUCCESS = "success"
# 开启后返回 "success",不返回 Status.SUCCESS
为什么企业用 :
接口返回干净、规范
8. ser_json_tz = False
作用 :时间不自动加时区
为什么企业用 :
避免前端时间错乱
三、企业级 万能通用模型基类
真实企业项目都会写一个 BaseModel 让所有模型继承:
python
from pydantic import BaseModel as PydanticBaseModel
class BaseModel(PydanticBaseModel):
model_config = {
"from_attributes": True,
"extra": "forbid",
"str_strip_whitespace": True,
"populate_by_name": True,
"coerce_numbers": True,
"use_enum_values": True
}
以后所有模型直接继承:
python
class User(BaseModel):
name: str
age: int
✅ 自动拥有全部企业级配置!
四、一句话总结
model_config 不是给文档看示例的,是控制模型行为、保证安全、规范、稳定的核心配置!
Fastapi 响应数据
- Fastapi 响应数据都会自动将返回结果转换成 json 格式,发送给客户端(给人看的)。也就是不管你路由函数返回的是字典,还是Pydantic模型实例,都会自动转换成json格式。
依赖注入
- 依赖注入:一种设计模式,让你可以将通用的逻辑(如数据库连接、身份验证、参数校验等)提取为可复用的组件,然后在路由中按需使用。Fastapi会在执行路由函数之前自动调用依赖函数,并将返回值传递给路由函数。
依赖函数和路径操作函数使用相同的参数声明方式,FastAPI 会自动解析依赖函数的参数。这意味着依赖函数也可以使用查询参数、路径参数、请求体等。
依赖函数里可以直接写:
查询参数 q: str
路径参数 user_id: int
请求头 token: str = Header()
Cookie session_id: str = Cookie()
请求体模型 user: User
甚至其他依赖
FastAPI 全部自动解析。
类作为依赖
使用类作为依赖
bash
class CommonQueryParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 100):
self.q = q
self.skip = skip
self.limit = limit
# 使用类作为依赖
@app.get("/items/")
async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
return {"q": commons.q, "skip": commons.skip, "limit": commons.limit}
-
Annotated: 是 Python 官方语法(3.9+)作用:给类型加 "附加信息"
格式:
bashAnnotated[类型, 附加信息1, 附加信息2...] -
Depends() 是什么?
平时我们写依赖是:
bashDepends(函数名)但这里是类,不是函数,所以 FastAPI 允许你简写:
bashDepends() # 自动用前面的类作为依赖
下面两种写法功能完全一样!
写法 A(你给的,优雅)
bash
async def read_items(commons: Annotated[CommonQueryParams, Depends()]):
写法 B(原始写法,啰嗦)
bash
async def read_items(commons: CommonQueryParams = Depends()):
- 为什么要用 Annotated?好处是什么?
-
类型更干净
不用写 = Depends() 在后面
-
官方推荐风格
-
可以放多个依赖 / 元数据
bashAnnotated[User, Depends(get_user), Depends(check_token)] -
代码更统一、更优雅
-
类作为依赖,同时使用多个 的正确写法
一个接口,想用 A 类依赖 + B 类依赖,两个都要,怎么写?
一、先准备两个类依赖(示例)
python
from typing import Annotated
from fastapi import Depends, FastAPI
app = FastAPI()
# 类依赖 1:公共查询参数
class CommonParams:
def __init__(self, q: str | None = None, skip: int = 0, limit: int = 10):
self.q = q
self.skip = skip
self.limit = limit
# 类依赖 2:鉴权(比如 token 校验)
class AuthCheck:
def __init__(self, token: str = "default"):
self.token = token
if self.token != "valid":
raise Exception("无效token")
二、同时使用 多个类依赖 的 3 种写法(任选)
写法 1:最标准、最推荐(Annotated)
python
@app.get("/items")
async def get_items(
# 第一个类依赖
params: Annotated[CommonParams, Depends()],
# 第二个类依赖
auth: Annotated[AuthCheck, Depends()]
):
return {
"q": params.q,
"skip": params.skip,
"token": auth.token
}
✅ 直接写多个参数,每个都是一个类依赖
写法 2:老式写法(不用 Annotated)
python
@app.get("/items")
async def get_items(
params: CommonParams = Depends(),
auth: AuthCheck = Depends()
):
return {
"q": params.q,
"token": auth.token
}
✅ 和上面功能完全一样,只是写法旧一点
写法 3:在装饰器里批量注入(不需要返回值时)
python
@app.get(
"/items",
dependencies=[Depends(AuthCheck), Depends(CommonParams)]
)
async def get_items():
return {"msg": "同时通过了两个类依赖校验"}
✅ 适合只做校验,不需要拿到返回值的场景
(如鉴权、日志、限流)
三、一句话终极总结
多个类依赖 = 函数参数里写多个,每个都用 Annotated 或 = Depends()
就像这样:
python
async def 接口(
依赖1: Annotated[类1, Depends()],
依赖2: Annotated[类2, Depends()]
):
四、总结
我再给你一句最精简的:
类依赖想写多少个就写多少个,和函数参数一样,直接并列写就行!
什么叫「对整个路由组使用依赖」?
这里会学习一个新的词汇:路由组,以及学习如何优雅的给一组路由设置依赖
一句话:
给一组接口,一次性加上同一个依赖,不用每个接口都重复写。
就像:
给整个班级 设置门禁,不是给每个学生单独设置。
一、先看你这段代码
python
# 依赖:校验 API Key
async def verify_api_key(x_api_key: str = Header()):
if x_api_key != "secret-key":
raise HTTPException(...)
你给两个接口都加了依赖:
python
@app.get("/items/", dependencies=[Depends(verify_api_key)])
@app.get("/users/", dependencies=[Depends(verify_api_key)])
这就是:
每个接口自己带依赖(重复代码)
二、真正的「路由组 + 统一依赖」长这样
FastAPI 有个东西叫 APIRouter(路由分组)
作用:
把一堆接口归为一组,统一加前缀、统一加依赖!
代码示例(一看就懂)
python
from fastapi import APIRouter
# 1. 创建一个路由组(比如叫:需要鉴权的接口组)
router = APIRouter(
prefix="/api", # 统一前缀
dependencies=[Depends(verify_api_key)] # 统一依赖!
)
# 2. 下面所有接口,自动带上上面的依赖!不用再写!
@router.get("/items")
def read_items():
return [{"item": "Foo"}]
@router.get("/users")
def read_users():
return [{"user": "Bar"}]
# 3. 把路由组挂载到 app
app.include_router(router)
效果
/api/items→ 自动校验 API Key/api/users→ 自动校验 API Key
你不用在每个接口上写 dependencies!
三、终极通俗理解
没有路由组:
每个接口 → 自己带钥匙(自己写依赖)
有路由组:
整个组 → 大门统一上锁,里面所有接口都受保护
四、三种使用依赖的方式(必背)
1. 接口函数内使用(拿到返回值)
python
def read_items(auth=Depends(verify_api_key)):
2. 装饰器里单独给一个接口用
python
@app.get("/items", dependencies=[Depends(verify_api_key)])
3. 给整个路由组用(最常用!)
python
router = APIRouter(dependencies=[Depends(verify_api_key)])
五、一句话总结(超级好记)
路由组 = 给一堆接口批量设置统一规则(前缀、依赖、标签)
dependencies=[...] = 给这一组全部自动鉴权
你现在懂了吗?
我再给你一句最精简的:
给路由组加依赖 = 批量给一组接口加鉴权/校验,不用重复写代码。
字典 跟 json 的区别?
长得很像,但完全不是一回事!
- 字典 (dict) :是 Python 内存里的对象 ,给代码用的
- JSON :是 纯文本字符串 ,给网络/文件用的
直观对比
1. Python 字典(代码里的)
python
# 这是 Python 对象,运行在内存里
person = {
"name": "小明",
"age": 20,
"is_student": True, # 大写 T
"hobby": None # None 表示空
}
特点:
- 引号 :单双引号都行
'" - 布尔值 :
True/False(大写) - 空值 :
None - 可以存函数、对象、日期等复杂内容
2. JSON(文本字符串)
json
{
"name": "小明",
"age": 20,
"is_student": true, # 小写 t
"hobby": null # null
}
特点:
- 只能用双引号
",绝对不能用单引号 - 布尔值:
true/false(小写) - 空值:
null - 只能是纯文本,不能存函数/对象
核心区别
| 特性 | Python 字典 (dict) | JSON |
|---|---|---|
| 本质 | 内存数据结构 | 纯文本字符串 |
| 引号 | 单/双引号都可以 | 必须双引号 |
| 布尔值 | True False |
true false |
| 空值 | None |
null |
| 用途 | 代码里存数据 | 网络传输、存文件 |
| 注释 | 支持 | 不支持 |
它们的关系:转换
Python 提供了 json 库,帮你互相转换:
字典 → JSON(序列化)
python
import json
# 字典
person = {"name": "小明", "age": 20}
# 转成 JSON 字符串
json_str = json.dumps(person)
print(type(json_str)) # <class 'str'> 变成文本了!
JSON → 字典(反序列化)
python
# JSON 字符串
json_str = '{"name": "小明", "age": 20}'
# 转成字典
person = json.loads(json_str)
print(type(person)) # <class 'dict'> 变回代码对象
最简单的理解
- 字典 = 你脑子里想的信息
- JSON = 写在纸上、发给别人的文字
你要把想法传给别人,必须写下来(转 JSON)
别人收到文字,要理解必须变成想法(转字典)
请求头和 Cookie是什么?
一、请求头 Request Headers
浏览器/客户端发请求时,附带的附加信息包,放在请求报文头部,服务端用来识别、校验、适配请求。
常见作用:
- 告诉服务器客户端类型、浏览器、系统
- 携带认证令牌、权限标识
- 声明能接收的数据格式、编码
- 跨域、防盗链校验
常用字段
User-Agent:客户端设备与浏览器信息Content-Type:请求体数据格式(JSON/表单)Authorization:登录令牌鉴权Referer:来源页面地址
二、Cookie
服务器下发、存在浏览器本地的小型文本数据,跟随每次请求自动带回服务端。
核心用途
- 记录登录状态,维持会话
- 保存用户偏好、临时标识
- 识别同一访客身份
特点
- 大小有限,只存简单字符串
- 可设置过期时间
- 每次同源请求自动携带发送
三者关系直白类比
- 请求体:真正要提交的业务数据(表单、参数)
- 请求头:附带说明、身份凭证、格式说明
- Cookie:随身身份小卡片,自动跟着请求走
一句话区分
请求头是通用附加说明;Cookie是存本地、自动携带的身份小数据。
请求头和cookie在fastapi中的作用以及使用场景有哪些?
一、先记住一句话
请求头 = 快递单上的所有信息
Cookie = 快递单里的「身份贴条」
在 FastAPI 里:
- 请求头 :用来识别、鉴权、控制请求
- Cookie :用来记住用户、保持登录状态
二、请求头 Header 在 FastAPI 里的作用
作用
- 传递身份凭证(token)
- 告诉接口数据格式
- 做权限校验
- 做跨域、防盗链、设备识别
FastAPI 中怎么用?
1. 获取请求头
python
from fastapi import FastAPI, Header
app = FastAPI()
@app.get("/")
def read_root(user_agent: str = Header()):
return {"你的浏览器信息": user_agent}
2. 最常用场景:从请求头拿 Token 登录鉴权
python
@app.get("/user/info")
def user_info(authorization: str = Header()):
# 校验 token 是否正确
if authorization != "Bearer 123456":
return {"msg": "未登录"}
return {"msg": "已登录,欢迎回来"}
请求头使用场景
- 登录鉴权(最常用)
- 接口版本控制
- 传递语言、时区
- 客户端设备判断
- 接口限流、权限控制
三、Cookie 在 FastAPI 里的作用
作用
- 自动记住用户(不用每次都传 token)
- 保持登录状态
- 存储少量用户信息
- 识别访客
FastAPI 中怎么用?
1. 获取 Cookie
python
from fastapi import Cookie
@app.get("/get-cookie")
def get_cookie(session_id: str | None = Cookie(None)):
return {"你的会话ID": session_id}
2. 设置 Cookie(登录成功后下发)
python
from fastapi import Response
@app.get("/login")
def login(response: Response):
# 给浏览器设置 cookie
response.set_cookie(key="session_id", value="abc123def")
return {"msg": "登录成功,cookie已下发"}
Cookie 使用场景
- 网站登录状态保持
- 记住我(7天免登录)
- 购物车、用户偏好
- 会话识别
- 后台管理系统登录
四、最关键区别(面试必考)
请求头 Header
- 手动传
- 适合接口、APP、小程序
- 更安全、更灵活
- 前后端分离首选
Cookie
- 浏览器自动传
- 适合网站、网页
- 自动维持登录
- 传统 Web 项目用得多
五、FastAPI 开发中最真实的使用场景
1. 90% 前后端分离项目
请求头 + Token
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
2. 管理后台、网页项目
Cookie + Session
- 登录成功 → 下发 Cookie
- 下次访问 → 浏览器自动带上
- FastAPI 直接读取,判断是否登录
3. 文件下载、接口加密
请求头带签名、时间戳等。
4. 多语言接口
请求头带 Accept-Language 返回对应语言。
六、超级简单总结
请求头 Header
- 作用:鉴权、传附加信息、控制请求
- 场景:登录 token、版本、设备、格式
- 特点:手动传,前后端分离主流
Cookie
- 作用:记住用户、保持登录
- 场景:网站登录、购物车、会话
- 特点:浏览器自动带,适合网页
自定义响应头有什么作用以及应用场景是?
一、什么是自定义响应头?
就是 服务器在返回数据时,额外塞给客户端的一段"小信息" 。
它不在返回的 JSON 里,而是藏在响应的头部。
客户端(浏览器/前端)可以拿到,但用户看不见。
二、自定义响应头有什么用?(核心作用)
-
传递额外信息,不污染业务数据
不想把状态、版本、提示放进 JSON,就放响应头。
-
控制前端行为
让浏览器缓存、跨域、不缓存、重定向等。
-
安全控制
防劫持、防XSS、防盗链。
-
接口监控、调试、日志
传请求ID、处理时间、服务版本。
-
权限/状态标记
告诉前端是否需要刷新登录、限流等。
三、最常用的应用场景(真实开发 90% 都会用到)
1. 跨域配置(最最常用)
Access-Control-Allow-Origin: *
允许前端调用接口,解决跨域报错。
2. 禁止缓存 / 强制刷新
Cache-Control: no-cache
让浏览器每次都拿最新数据,不读本地缓存。
(登录接口、支付接口、实时数据必用)
3. 传递接口处理时间、请求唯一ID(日志排查)
X-Process-Time: 0.032
X-Request-ID: abc123def456
方便查问题:哪个请求慢?哪次调用出错?
4. 安全防护(必加)
X-Content-Type-Options: nosniff
X-XSS-Protection: 1
防止网页被劫持、XSS攻击。
5. 告诉前端:Token 快过期了,需要刷新
X-Token-Expire-Soon: true
前端自动跳登录或刷新token。
6. 接口版本控制
X-API-Version: 2.0
区分新旧接口。
7. 文件下载时告诉浏览器文件名
Content-Disposition: attachment; filename=report.pdf
8. 限流提示
X-RateLimit-Remaining: 5
告诉用户还能调用几次接口。
四、FastAPI 中如何自定义响应头?(直接复制用)
方式1:单个接口返回自定义头
python
from fastapi import FastAPI, Response
app = FastAPI()
@app.get("/api/data")
def get_data(response: Response):
# 自定义响应头
response.headers["X-Process-Time"] = "0.025"
response.headers["X-API-Version"] = "2.0"
response.headers["Cache-Control"] = "no-cache"
return {"msg": "数据返回成功"}
方式2:全局统一加响应头(所有接口都带)
python
from fastapi import FastAPI, Request, Response
from fastapi.responses import JSONResponse
app = FastAPI()
@app.middleware("http")
async def add_custom_header(request: Request, call_next):
response = await call_next(request)
# 统一给所有接口加响应头
response.headers["X-Server"] = "FastAPI-Server"
response.headers["X-Env"] = "Production"
return response
五、一句话记住自定义响应头
不污染返回数据,又能给前端传秘密信息、控制行为、加强安全、方便调试。
它是后端和前端之间的悄悄话通道。
六、最简单总结(必背)
自定义响应头的作用:
- 传额外信息
- 控制浏览器/前端行为
- 加强安全
- 方便调试、日志、监控
使用场景:
- 跨域
- 缓存控制
- 请求ID、耗时
- 安全防护
- Token 过期提醒
- 接口版本
- 文件下载