FastApi快速入门一:基础语法
一、简介
FastAPI 是一个现代、高性能的 Python Web 框架,用于构建 API。
它基于Starlette(异步 Web 框架)和Pydantic(数据验证库),结合了异步编程和类型提示,兼顾开发效率与运行性能。
·使用 Uvicorn(ASGI服务器),支持高并发请求。
·FastAPI:~3000 请求/秒(异步,轻量)
·Flask:~1000 请求/秒(同步,受WSGI 限制)
·Django:~800 请求/秒(同步,ORM 和中间件开销较大)
·支持 async/await 语法,适合高并发场景(如实时聊天、流处理)
·比传统同步框架(如 Flask)更适合现代 Web 应用
二、环境搭建
##创建虚拟环境
conda create -n fastapi_env python=3.13.5
##激活虚拟环境
conda activate fastapi_env
##退出虚拟环境
conda deactivate
##安装FastAPI及其依赖
##在虚拟环境中安装FastAPI (安装的是最新的版本)
pip install "fastapi[standard]"
##指定版本安装
pip install fastapi==0.115.12
pip install uvicorn==0.34.2
三、快速入门
1、第一个程序与启动
from typing import Union;
from fastapi import FastAPI;
app = FastAPI();
"""
1、普通get
"""
@app.get("/hello")
async def hello():
return {"message": "Hello World"};
"""
2、带参get
eg: localhost:8000/query/123?item_name=123
"""
@app.get("/query/{item_id}")
def read_item(item_id: int, item_name: Union[str, None] = None):
return {"item_id": item_id, "item_name": item_name};
##启动服务
##第一种方式
uvicorn filename:app_name --reload ##加上--reload后,修改代码后会自动重新加载
##第二种方式
fastapi dev filename.py
##第三种方式
python filename.py
#需要在文件中加上如下代码
import uvicorn;
if __name__ == "__main__":
uvicorn.run("filename:app_name",host="127.0.0.1",port=8000,reload=True); #加reload必须这种写法
或
uvicorn.run(app_name,host="127.0.0.1",port=8000)
##查看文档
http://127.0.0.1/docs
http://127.0.0.1/redoc
2、路径参数
"""
路径参数
"""
import uvicorn
from fastapi import FastAPI;
app = FastAPI();
@app.get("/params1/{id}")
def read_params_1(id):
return {"id": id};
@app.get("/params2/{id}/{name}")
def read_params_2(id, name):
return {"id": id, "name": name};
@app.get("/params3/{id}/{name}")
def read_params_3(id: int, name: str):
return {"id": id, "name": name};
if __name__ == '__main__':
uvicorn.run("01_pathParam:app", host="127.0.0.1", port=8000, reload=True);
3、查询参数
##语法
url ? 参数1=值 & 参数2=值
"""
查询参数
"""
import uvicorn;
from fastapi import FastAPI;
app = FastAPI();
@app.get("/queryParams1")
def query_params_1(pages: int, limit: int):
return {"pages": pages, "limit": limit};
@app.get("/queryParams2")
def query_params_2(pages: int, limit: int = 10):
return {"pages": pages, "limit": limit};
@app.get("/queryParams3/{pages}")
def query_params_3(pages: int, limit: int = 10):
return {"pages": pages, "limit": limit};
if __name__ == "__main__":
uvicorn.run("02_queryParam:app", host="127.0.0.1", port=8000, reload=True);
4、请求体
"""
查询参数-->请求体参数
"""
import uvicorn
from fastapi import FastAPI;
from pydantic import BaseModel;
class UserClass(BaseModel):
username: str;
password: str;
gender: str | None;
age: int = 20;
app = FastAPI();
# 字典类-->请求体参数
@app.post("/queryBody1")
def query_body_1(userDict: dict):
return userDict;
# 类-->请求体参数
@app.post("/queryBody2")
def query_body_2(userClass: UserClass): # 指定 对应的类
return userClass;
if __name__ == "__main__":
uvicorn.run("03_queryBody:app", host="0.0.0.0", port=8000, reload=True);
5、请求参数验证
5.1、类型注解方式
"""
请求参数验证:
类型注解方式
"""
from typing import Union,Optional,List;
import uvicorn;
from fastapi import FastAPI;
app = FastAPI();
# 路径参数验证——指定参数是字符串类型
@app.get("/paramsValid1/{param}")
def paramValid1(param: str):
return param;
# 路径参数验证——指定参数是字符串或整数类型,默认值为10
@app.get("/paramsValid2/{param}")
def paramsValid2(param: Union[str, int] = 10):
return param;
# 路径参数验证——指定参数是可选的字符串类型,默认值为None
@app.get("/paramsValid3")
def paramsValid3(param: Optional[str] = None):
return param;
if __name__ == "__main__":
uvicorn.run("04_paramsValid:app",host="127.0.0.1",port=8000,reload=True);
5.2、Query方式
| 参数名 | 类型 | 默认值 | 说明 | 示例 |
|---|
default / ... | Any | None | 设置参数的默认值。使用 ... 表示该参数为必填项。 | param: int = Query(10) param: int = Query(...)(必填) |
alias | str | None | 指定参数在 URL 中使用的别名(可用于含特殊字符或不符合 Python 命名规范的参数名)。 | field_name: str = Query(None, alias="field-name") → /items?field-name=value |
title | str | None | 为参数设置标题,主要用于 API 文档(如 Swagger)显示。 | param: str = Query(None, title="User ID") |
description | str | None | 描述该参数用途,显示在 API 文档中。 | param: str = Query(None, description="用户名,用于搜索") |
deprecated | bool | False | 标记该参数已弃用,在文档中显示警告。 | param: str = Query(None, deprecated=True) |
include_in_schema | bool | True | 是否将该参数包含在生成的 OpenAPI 文档中。设为 False 可隐藏参数。 | debug: bool = Query(False, include_in_schema=False) |
数字验证 int /float
| 参数名 | 类型 | 默认值 | 说明 | 示例 |
|---|
gt | float | None | 值必须大于指定值(greater than) | age: int = Query(..., gt=0) |
ge | float | None | 值必须大于等于指定值(greater than or equal) | age: int = Query(1, ge=1) |
lt | float | None | 值必须小于指定值(less than) | score: float = Query(None, lt=100.0) |
le | float | None | 值必须小于等于指定值 | score: float = Query(None, le=100.0) |
字符串验证
| 参数名 | 类型 | 默认值 | 说明 | 示例 |
|---|
min_length | int | None | 字符串最小长度 | name: str = Query(..., min_length=3) |
max_length | int | None | 字符串最大长度 | name: str = Query("abc", max_length=50) |
regex | str | None | 字符串必须匹配正则表达式 | code: str = Query(..., regex=r"^\d{3}-\d{2}$") |
列表/多个值验证
| 参数名 | 类型 | 默认值 | 说明 | 示例 |
|---|
min_items | int | None | 列表最小项数(需配合 List[T] 使用) | ids: list[int] = Query(None, min_items=1) |
max_items | int | None | 列表最大项数 | tags: list[str] = Query(None, max_items=5) |
"""
参数验证
query方式
"""
import uvicorn;
from fastapi import FastAPI,Query;
app =FastAPI();
@app.get("/paramsValid1")
def paramsValid1(param: str = Query(123)):
return param;
@app.get("/paramsValid2")
def paramsValid2(param: str = Query(...)):
return param;
@app.get("/paramsValid3")
def paramsValid3(param: str = Query(...,min_length=3,max_length=5)):
return param;
@app.get("/paramsValid4")
def paramsValid4(param: int = Query(...,gt=10,lt=20)):
return param;
@app.get("/paramsValid5")
def paramsValid5(param: int = Query(...,alias="id")):
return param;
if __name__=="__main__":
uvicorn.run("05_paramsValid:app",host="127.0.0.1",port=8000,reload=True);
5.3、path方式
具体参数雷同query
"""
参数验证
query方式
"""
import uvicorn;
from fastapi import FastAPI,Query;
app =FastAPI();
@app.get("/paramsValid1/{id}")
def paramsValid1(id: int = Path(...,lt=10,gt=20)):
return id;
if __name__=="__main__":
uvicorn.run("06_paramsValid:app",host="127.0.0.1",port=8000,reload=True);
5.4、field方式
具体参数雷同query和path
from fastapi import FastAPI, Body
from pydantic import BaseModel, Field
from typing import List, Optional
app = FastAPI()
class UserCreate(BaseModel):
user_name: str = Field(
...,
min_length=3,
max_length=20,
regex=r"^[a-zA-Z0-9_]+$",
description="用户名,仅支持字母、数字、下划线",
example="alice123"
)
age: int = Field(
...,
gt=0,
le=150,
description="年龄,必须在1-150之间"
)
email: Optional[str] = Field(
None,
regex=r"^[^@]+@[^@]+\.[^@]+$",
description="邮箱格式"
)
tags: List[str] = Field(
None,
min_items=1,
max_items=5,
description="用户标签,最多5个"
)
internal_key: str = Field(
None,
include_in_schema=False
)
@app.post("/users")
def create_user(user: UserCreate = Body(...)):
return {"user": user}
6、表单数据
使用表单需预先安装
pip install python-multipart
"""
表单数据
"""
import uvicorn
from fastapi import FastAPI, Form;
from pydantic import BaseModel
app = FastAPI();
@app.post("/login1")
def formLogin1(username: str = Form(...), password: str = Form(...)):
return {"username": username, "password": password}
class User(BaseModel):
username: str;
password: str;
@app.post("/login2")
def formLogin2(user : User = Form(...)):
return {"username": user.username, "password": user.password}
if __name__ == "__main__":
uvicorn.run("06_formData:app", host="0.0.0.0", port=8000,reload=True);
7、异步请求
"""
异步方法
"""
import uvicorn;
from fastapi import FastAPI;
app = FastAPI();
@app.get("/login2")
async def getUserInfo():
return {"username": "admin", "password": "123456"}
if __name__ == "__main__":
uvicorn.run("07_asyncMethod:app", host="0.0.0.0", port=8000,reload=True);
8、文件上传
#方法一:
byte 适合小文件 10M以内 ---> 会将文件一次性加载到内存中
#方法二:
UploadFile 推荐 (大文件)
"""
文件上传1
byte 上传 适合小文件(全部加载到内存中)
uploadFile 上传
"""
import asyncio
import uvicorn;
from fastapi import FastAPI,File,UploadFile;
app = FastAPI();
@app.post("/upload")
def uploadFile(file: bytes = File(...)):
contents = file.decode("utf-8");
return {"content": contents};
@app.post("/upload2")
async def uploadFile2(file: UploadFile):
while chunk := await file.read(1024):
print(chunk);
return {"filename": file.filename};
if __name__ == "__main__":
uvicorn.run("08_fileUpload:app", host="127.0.0.1", port=8000,reload=True);
9、请求对象Request
获取用户请求信息
"""
Requet访问对象
"""
import uvicorn;
from fastapi import FastAPI, Request;
app = FastAPI();
@app.get("/getClientInfo")
async def getClientInfo(request: Request):
"""
获取客户端用户信息
:param request:
:return:
"""
return {
"请求IP": request.client.host,
"请求URL": request.url,
"请求方法": request.method,
"请求参数": request.query_params,
"请求头": request.headers,
"请求Cookie": request.cookies,
"请求path_params": request.path_params,
"user_agent": request.headers.get("user-agent")
}
if __name__ == "__main__":
uvicorn.run(app="09_request:app", host="127.0.0.1", port=8000, reload=True);
10、响应数据类型
10.1、JSON格式
FastAPI天然支持通过Python字典或Pydantic模型自动序列化为JSON响应
"""
响应JSON数据
"""
from typing import Union,TypeVar,Generic
import uvicorn;
from fastapi import FastAPI;
from pydantic import BaseModel;
app = FastAPI();
class Item(BaseModel):
id: int
name: str
price: float
T = TypeVar('T');
class SuccessResponse(BaseModel, Generic[T]):
code: int = 200
msg: str = "success"
data: Item
class ErrorResponse(BaseModel, Generic[T]):
code: int = 400
msg: str = "error"
data: None = None
@app.get("/item/dict")
def getItemDict():
"""
以字典形式返回信息
"""
return {
"id": 1,
"name": "item1",
"price": 100
};
@app.get("/item/model1")
def getItemModel1():
"""
以模型形式返回信息
"""
return Item(id=2, name="item2", price=200);
@app.get("/item/model2", response_model=Item)
def getItemModel2():
"""
以模型形式返回信息
"""
return Item(id=2, name="item2", price=200);
@app.get("/item/model3/{item_id}", response_model=Union[SuccessResponse[Item], ErrorResponse[Item]])
def getItemModel3(item_id: int):
"""
以模型形式返回信息
"""
if item_id == 1:
return SuccessResponse(code=0, msg="success",data = Item(id=2, name="item2", price=200));
else:
return ErrorResponse[Item](code=1, msg="error");
if __name__ == "__main__":
uvicorn.run(app="10_response_json:app", host="127.0.0.1", port=8000, reload=True);
10.2、列表响应
用于分页查询或批量数据返回等
"""
以列表形式返回信息
"""
import uvicorn;
from fastapi import FastAPI;
from pydantic import BaseModel;
app = FastAPI();
class Item(BaseModel):
id: int
name: str
price: float
category: str = "apple";
@app.get("/items/normalList")
def getNormalList():
"""
以列表形式返回信息
"""
return ["item1", "item2", "item3"];
@app.get("/items/modelList")
def getModelList():
"""
以模型列表形式返回信息
"""
myList = [Item(id=i, name=f"item{i}", price=i*100, category="apple" if i % 2 == 0 else "orange") for i in
range(10)];
return myList;
if __name__ == "__main__":
uvicorn.run(app="11_response_list:app", host="127.0.0.1", port=8000, reload=True);
##注意:
"apple" if i % 2 == 0 else "orange" 这种写法是三元运算,不是简单的 if else
##三元运算语法:
value_if_true if condition else value_if_false
这个语法是 表达式(expression),不是语句(statement),所以它必须返回一个值,并且顺序是:
先写 满足条件时的值
再写 if 条件
然后 else
最后写 不满足条件时的值
10.3、文件响应
用于报表导出、文件下载等
文件响应的关键特点:
·内容类型:通过 Content-Type 头指定文件的 MIME 类型,
如text/plain (txt文件) text/csv (CSV文件)、 application/pdf (PDF文件)、application/vnd.ms-excel (Excel文件)
·文件内容:响应的 body包含文件的实际数据,可能是二进制(如 PDF、图片)或文本(如 CSV、JSON 文件)。
Content-Type 用于 告诉浏览器文件的类型是什么
Content-Disposition 用于 告诉浏览器如何处理响应体的内容,尤其是:是应该“在浏览器中直接显示”内容,还是“提示用户下载”为一个文件
Content-Disposition: inline (在浏览器中直接显示内容)显示图片、PDF、HTML 文件等
Content-Disposition: attachment; filename="filename.txt" (提示用户将响应内容保存为一个文件)文件直接下载(如导出 Excel、PDF、ZIP 等)
文本类型
| Content-Type | 说明 |
|---|
text/plain | 纯文本文件(.txt) |
text/html | HTML 页面 |
text/css | CSS 样式表 |
text/javascript | JavaScript 文件(现已不推荐,用 application/javascript) |
text/csv | CSV 表格文件 |
text/xml | XML 数据 |
应用类型
| Content-Type | 说明 |
|---|
application/json | 最常用! JSON 数据格式 |
application/xml | XML 数据 |
application/pdf | PDF 文件 |
application/zip | ZIP 压缩包 |
application/octet-stream | 二进制流数据(通用下载类型,常用于未知文件) |
application/xhtml+xml | XHTML 文档 |
application/javascript | JavaScript 文件(推荐用这个) |
application/x-www-form-urlencoded | 表单提交默认格式(如 <form> 提交) |
application/vnd.ms-excel | Excel 文件(.xls) |
application/vnd.openxmlformats-officedocument.spreadsheetml.sheet | Excel 文件(.xlsx) |
application/msword | Word 文档(.doc) |
application/vnd.openxmlformats-officedocument.wordprocessingml.document | Word 文件(.docx) |
表单类型
| Content-Type | 说明 |
|---|
application/x-www-form-urlencoded | 普通表单提交,数据被编码成 key=value&key2=value2 |
multipart/form-data | 用于上传文件的表单,支持二进制数据 |
图片类型
| Content-Type | 说明 |
|---|
image/jpeg | JPEG 图片(.jpg, .jpeg) |
image/png | PNG 图片(.png) |
image/gif | GIF 动图(.gif) |
image/webp | WebP 格式(现代网页推荐) |
image/svg+xml | SVG 矢量图 |
image/bmp | BMP 位图 |
image/tiff | TIFF 图像(专业用途) |
音频类型
| Content-Type | 说明 |
|---|
audio/mpeg | MP3 音频 |
audio/wav | WAV 音频 |
audio/ogg | Ogg 音频格式 |
audio/aac | AAC 音频 |
audio/webm | WebM 音频 |
视频类型
| Content-Type | 说明 |
|---|
video/mp4 | MP4 视频 |
video/mpeg | MPEG 视频 |
video/ogg | Ogg 视频 |
video/webm | WebM 视频(HTML5 推荐) |
video/quicktime | MOV 视频(苹果) |
"""
文件下载
"""
import uvicorn
from fastapi import FastAPI,File,UploadFile;
from fastapi.responses import Response,FileResponse;
from starlette.responses import StreamingResponse
app = FastAPI();
@app.get("/download/txt")
def downloadText():
"""
下载txt文件
"""
content = b"hello World";
return Response(
content=content,
media_type='text/plain',
headers={"Content-Disposition": "attachment; filename=test.txt"}
);
@app.get("/download/img")
def downloadImg():
return FileResponse(
path=r"D:\utils\壁纸\动漫\1.jpg",
media_type="image/png",
headers={"Content-Disposition": "attachment; filename=1.jpg"}
)
"""
将大文件切成小文件 1024表示1kb
"""
def generate_chunks(file_path: str, chunk_size: int = 1024*1024*5):
with open(file_path, "rb") as f:
while chunk := f.read(chunk_size):
yield chunk
@app.get("/download/pdf")
def downloadPdf():
"""
下载pdf文件
"""
return StreamingResponse(
content= generate_chunks(r"G:\LearnSpace\daily-code-notes\06、Python与大模型笔记\资料\LLM Universe.pdf",1024*1024*7),
media_type="application/pdf",
headers={"Content-Disposition": "attachment; filename=test.pdf"}
)
if __name__=='__main__':
uvicorn.run(app="12_response_file:app", host="127.0.0.1", port=8000, reload=True);
##其他解读
1、 := 海象运算符(Walrus Operator)
这是 Python 3.8+ 引入的新语法:赋值表达式,它可以在表达式中同时进行赋值和判断。
#传统写法(Python < 3.8)
while True:
chunk = f.read(chunk_size)
if not chunk: # 读完了(空 bytes)
break
yield chunk
#新写法
while chunk := f.read(chunk_size):
yield chunk
等价于:
先执行 f.read(chunk_size) 读取数据
把结果赋值给变量 chunk
判断 chunk 是否为真(即是否还有数据)
如果 chunk 是空(b''),循环结束
否则继续循环
💡 := 让你在 一个表达式中完成“读取 + 赋值 + 判断”
2、yield 生成器关键字
yield 是 Python 中**生成器(generator)**的核心关键字。
它的作用:
每次调用函数时,不返回所有结果,而是“逐个产出”结果
函数执行到 yield 时暂停,下次调用再继续
节省内存,适合处理大数据
# ❌ 普通函数:一次性返回所有数据(占内存)
def read_all(file_path):
with open(file_path, "rb") as f:
return f.read() # 整个文件一次性加载进内存
# ✅ 生成器函数:分块返回,边读边处理
def generate_chunks(file_path):
with open(file_path, "rb") as f:
while chunk := f.read(1024):
yield chunk # 每次只返回一块,不占内存
| 前缀 | 含义 | 示例 | 用途 |
|---|
b"..." | 字节字符串(bytes) | b"hello" | 二进制数据、文件、网络传输 |
f"..." | 格式化字符串(formatted) | f"Hello {name}" | 字符串插值(类似模板) |
r"..." | 原始字符串(raw) | r"C:\new\folder" | 忽略转义字符(如 \n, \t) |
10.4、其他类型响应
字符串响应、HTML响应、重定向响应、流式响应
"""
其他返回类型:字符串响应、HTML响应、重定向响应、流式响应
"""
import uvicorn
from fastapi import FastAPI
from fastapi.responses import HTMLResponse
from starlette.responses import RedirectResponse
from starlette.staticfiles import StaticFiles
app = FastAPI()
@app.get("/resp1")
async def resp1():
return "123我就是个普通字符串";
@app.get("/resp2",response_class=HTMLResponse)
async def resp2():
return "<a href='https://www.baidu.com'>我是一个html,点我跳转到百度</a>";
@app.get("/resp3")
async def resp3():
"""
重定向到resp2
"""
return RedirectResponse(url="/resp2")
app.mount("/templates", StaticFiles(directory="templates",html=True), name="templates")
if __name__ == "__main__":
uvicorn.run(app="13_response_other:app", host="127.0.0.1", port=8000,reload=True)