FastAPI 速通
文章目录
- [FastAPI 速通](#FastAPI 速通)
-
-
- 入门
-
- [Hello World](#Hello World)
- 路径、查询、请求体参数
- 响应类型、自定义响应数据格式
- 中间件、依赖注入
- ORM建表、路由中的使用
- 数据库操作
- 实战
-
- AI掘金头条新闻系统 (Toutiao News)
-
- [1-1 项目概述](#1-1 项目概述)
- [1-2 技术栈](#1-2 技术栈)
- [1-3 项目结构](#1-3 项目结构)
- [1-4 功能模块](#1-4 功能模块)
- [1-5 数据库设计](#1-5 数据库设计)
- [1-6 缓存设计](#1-6 缓存设计)
- [1-7 API 接口说明](#1-7 API 接口说明)
- [1-8 认证机制](#1-8 认证机制)
- [1-9 错误处理](#1-9 错误处理)
- [1-10 开发规范](#1-10 开发规范)
- [1-11 性能优化](#1-11 性能优化)
- [模块化路由、数据库和 ORM 配置](#模块化路由、数据库和 ORM 配置)
- 接口实现完整流程
-
入门
Hello World
python
from fastapi import FastAPI
# 创建 FastAPI 实例
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
@app.get("/hello/{name}")
async def say_hello(name: str):
return {"message": f"Hello {name}"}
文档接口/docs
路径、查询、请求体参数
python
from fastapi import FastAPI, Path, Query
from pydantic import BaseModel, Field
app = FastAPI()
# ==========================================
# 1. 路径参数 (Path Parameters)
# 来源:URL 路径中的变量,如 /book/123
# 校验:Path(...) 用于校验数值范围、字符串长度等
# ==========================================
@app.get("/book/{id}")
async def get_book(id: int = Path(default=..., gt=0, lt=101, description="书籍id, 取值范围1-100")):
return {"id": id, "title": f"这是第{id}本书"}
@app.get("/author/{name}")
async def get_author(name: str = Path(default=..., min_length=2, max_length=10)):
return {"msg": f"这是{name}的信息"}
# ==========================================
# 2. 查询参数 (Query Parameters)
# 来源:URL ?后面的键值对,如 /news?skip=0&limit=10
# 校验:Query(...) 用于设置默认值、描述和限制
# ==========================================
@app.get("/news/news_list")
async def get_news_list(
skip: int = Query(0, description="跳过的记录数", lt=100),
limit: int = Query(10, description="返回的记录数")
):
return {"skip": skip, "limit": limit}
# ==========================================
# 3. 请求体参数 (Request Body)
# 来源:POST/PUT 请求中的 JSON 数据
# 校验:Pydantic 模型 + Field(...)
# ==========================================
class User(BaseModel):
username: str = Field(default="张三", min_length=2, max_length=10, description="用户名")
password: str = Field(min_length=3, max_length=20)
@app.post("/register")
async def register(user: User):
return user
# 默认路由
@app.get("/")
async def root():
return {"message": "Hello World"}
响应类型、自定义响应数据格式
python
from fastapi import FastAPI
from fastapi.responses import HTMLResponse, FileResponse
from pydantic import BaseModel
app = FastAPI()
# ==========================================
# 1. 响应 HTML 格式
# 关键点:response_class=HTMLResponse
# 作用:告诉 FastAPI 不要返回 JSON,而是直接返回 HTML 字符串
# ==========================================
@app.get("/html", response_class=HTMLResponse)
async def get_html():
return "<h1>这是一级标题</h1>"
# ==========================================
# 2. 响应文件 (图片/文件下载)
# 关键点:FileResponse(path)
# 作用:自动处理文件流,设置正确的 Content-Type (如图片、PDF等)
# ==========================================
@app.get("/file")
async def get_file():
# 注意:实际运行时请确保该路径下存在文件,否则会报错
path = "./files/1.jpeg"
return FileResponse(path)
# ==========================================
# 3. 自定义响应数据格式 (Pydantic)
# 关键点:class News(BaseModel) + response_model=News
# 作用:
# 1. 数据校验:确保返回的数据符合模型定义
# 2. 文档生成:在 Swagger UI 中展示清晰的响应模型结构
# ==========================================
# 定义数据模型
class News(BaseModel):
id: int
title: str
content: str
# 使用模型
@app.get("/news/{id}", response_model=News)
async def get_news(id: int):
# 这里的字典数据会被 Pydantic 自动转换为 News 对象并校验
return {
"id": id,
"title": f"这是第{id}本书",
"content": "这是一本好书"
}
# 默认 JSON 响应
@app.get("/")
async def root():
return {"message": "Hello World"}
中间件、依赖注入
python
from fastapi import FastAPI, Query, Depends
app = FastAPI()
# ==========================================
# 1. 中间件 (Middleware)
# 执行顺序:自下而上(装饰器模式,先定义的在外层)
# 流程:中间件1 Start -> 中间件2 Start -> 路由处理 -> 中间件2 End -> 中间件1 End
# ==========================================
@app.middleware("http")
async def middleware_2(request, call_next):
print("中间件2: 请求处理前 (内层)")
response = await call_next(request) # 调用后续处理(路由或其他中间件)
print("中间件2: 响应处理后 (内层)")
return response
@app.middleware("http")
async def middleware_1(request, call_next):
print("中间件1: 请求处理前 (外层)")
response = await call_next(request)
print("中间件1: 响应处理后 (外层)")
return response
# ==========================================
# 2. 依赖注入 (Dependency Injection)
# 作用:代码复用(如分页、鉴权),逻辑与路由分离
# ==========================================
# 1. 定义依赖项(公共逻辑:分页参数)
async def common_pagination(
skip: int = Query(0, ge=0, description="跳过数量"),
limit: int = Query(10, le=60, description="限制数量")
):
# 这里可以处理复杂的逻辑,最后返回结果
return {"skip": skip, "limit": limit}
# 2. 路由中使用依赖注入
@app.get("/news/news_list")
async def get_news_list(pagination=Depends(common_pagination)):
# 直接使用注入的结果
return {"msg": "新闻列表", "params": pagination}
@app.get("/user/user_list")
async def get_user_list(pagination=Depends(common_pagination)):
# 不同的路由复用同一个依赖项
return {"msg": "用户列表", "params": pagination}
@app.get("/")
async def root():
return {"message": "Hello World"}
ORM建表、路由中的使用
python
from datetime import datetime
from fastapi import FastAPI, Depends
from sqlalchemy import DateTime, func, String, Float, select
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
app = FastAPI()
# ==========================================
# 1. 数据库连接与建表配置 (公共底座)
# ==========================================
# 1.1 创建异步引擎
ASYNC_DATABASE_URL = "mysql+aiomysql://root:123456@localhost:3306/FastAPI_first?charset=utf8"
async_engine = create_async_engine(
ASYNC_DATABASE_URL,
echo=True, # 输出SQL日志
pool_size=10, # 连接池大小
max_overflow=20 # 额外连接数
)
# 1.2 定义基类 (包含公共时间字段)
class Base(DeclarativeBase):
create_time: Mapped[datetime] = mapped_column(DateTime, default=func.now(), comment="创建时间")
update_time: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now(), comment="修改时间")
# 1.3 定义具体模型 (书籍表)
class Book(Base):
__tablename__ = "book"
id: Mapped[int] = mapped_column(primary_key=True, comment="书籍id")
bookname: Mapped[str] = mapped_column(String(255), comment="书名")
author: Mapped[str] = mapped_column(String(255), comment="作者")
price: Mapped[float] = mapped_column(Float, comment="价格")
publisher: Mapped[str] = mapped_column(String(255), comment="出版社")
# 1.4 应用启动时自动建表
@app.on_event("startup")
async def startup_event():
async with async_engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
# ==========================================
# 2. 路由中的使用 (依赖注入)
# ==========================================
# 2.1 创建会话工厂
AsyncSessionLocal = async_sessionmaker(
bind=async_engine,
class_=AsyncSession,
expire_on_commit=False # 提交后对象不过期
)
# 2.2 定义依赖项 (核心:获取数据库连接 + 自动提交/回滚)
async def get_database():
async with AsyncSessionLocal() as session:
try:
yield session # 1. 提供给路由使用
await session.commit() # 2. 无异常则提交
except Exception:
await session.rollback() # 3. 有异常则回滚
raise
finally:
await session.close() # 4. 最后关闭连接
# 2.3 路由示例:使用依赖注入查询数据
@app.get("/book/books")
async def get_book_list(db: AsyncSession = Depends(get_database)):
# 执行查询语句
result = await db.execute(select(Book))
books = result.scalars().all() # 获取所有结果
return books
数据库操作
python
from datetime import datetime
from fastapi import FastAPI, Depends, HTTPException
from sqlalchemy import DateTime, func, String, Float, select
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from pydantic import BaseModel
# ========== 公共底座(这部分通常只写一次,无需频繁修改)==========
app = FastAPI()
# 1. 数据库连接(引擎)
ASYNC_DATABASE_URL = "mysql+aiomysql://root:123456@localhost:3306/FastAPI_first?charset=utf8"
async_engine = create_async_engine(ASYNC_DATABASE_URL, echo=True, pool_size=10, max_overflow=20)
# 2. ORM 基类与模型
class Base(DeclarativeBase):
create_time: Mapped[datetime] = mapped_column(DateTime, default=func.now(), comment="创建时间")
update_time: Mapped[datetime] = mapped_column(DateTime, default=func.now(), onupdate=func.now(), comment="修改时间")
class Book(Base):
__tablename__ = "book"
id: Mapped[int] = mapped_column(primary_key=True, comment="书籍id")
bookname: Mapped[str] = mapped_column(String(255), comment="书名")
author: Mapped[str] = mapped_column(String(255), comment="作者")
price: Mapped[float] = mapped_column(Float, comment="价格")
publisher: Mapped[str] = mapped_column(String(255), comment="出版社")
# 3. 依赖项:获取数据库会话
AsyncSessionLocal = async_sessionmaker(bind=async_engine, class_=AsyncSession, expire_on_commit=False)
async def get_database():
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
finally:
await session.close()
# 4. 启动事件:建表
@app.on_event("startup")
async def startup_event():
async with async_engine.begin() as conn:
await conn.run_sync(Base.metadata.create_all)
# ========== 核心业务逻辑 ==========
# 1. 查询数据 (Query)
# 需求:根据主键获取单条数据
@app.get("/book/get_book/{book_id}")
async def get_book(book_id: int, db: AsyncSession = Depends(get_database)):
book = await db.get(Book, book_id) # 根据主键查询
return book
# 需求:条件查询 (价格大于等于200)
@app.get("/book/search_price")
async def search_by_price(db: AsyncSession = Depends(get_database)):
result = await db.execute(select(Book).where(Book.price >= 200))
books = result.scalars().all()
return books
# 需求:复杂条件 (模糊查询、逻辑运算、包含)
@app.get("/book/search_complex")
async def search_complex(db: AsyncSession = Depends(get_database)):
# 模糊查询: 作者以"曹"开头;逻辑或: 价格大于100;包含: ID在列表中
id_list = [1, 3, 5, 7]
result = await db.execute(
select(Book).where(
(Book.author.like("曹%")) |
(Book.price > 100) |
(Book.id.in_(id_list))
)
)
return result.scalars().all()
# 需求:聚合查询 (统计数量、最大值、求和、平均值)
@app.get("/book/stats")
async def get_stats(db: AsyncSession = Depends(get_database)):
# count: 统计, max: 最大, sum: 求和, avg: 平均
count = await db.execute(select(func.count(Book.id)))
avg_price = await db.execute(select(func.avg(Book.price)))
return {
"total_count": count.scalar(),
"average_price": avg_price.scalar()
}
# 需求:分页查询
@app.get("/book/pagination")
async def get_paginated(page: int = 1, page_size: int = 3, db: AsyncSession = Depends(get_database)):
skip = (page - 1) * page_size
stmt = select(Book).offset(skip).limit(page_size)
result = await db.execute(stmt)
return result.scalars().all()
# 2. 新增数据 (Create)
class BookCreate(BaseModel):
bookname: str
author: str
price: float
publisher: str
@app.post("/book/add_book")
async def add_book(book: BookCreate, db: AsyncSession = Depends(get_database)):
book_obj = Book(**book.dict()) # 将请求体数据转为ORM对象
db.add(book_obj) # 添加到会话
# 注意:commit在依赖项中统一处理了
return {"msg": "新增成功", "data": book}
# 3. 更新数据 (Update)
class BookUpdate(BaseModel):
bookname: str
author: str
price: float
publisher: str
@app.put("/book/update_book/{book_id}")
async def update_book(book_id: int, data: BookUpdate, db: AsyncSession = Depends(get_database)):
# 1. 查找
db_book = await db.get(Book, book_id)
if not db_book:
raise HTTPException(status_code=404, detail="查无此书")
# 2. 赋值修改
db_book.bookname = data.bookname
db_book.author = data.author
db_book.price = data.price
db_book.publisher = data.publisher
# 提交在依赖项中处理
return {"msg": "更新成功", "data": db_book}
# 4. 删除数据 (Delete)
@app.delete("/book/delete_book/{book_id}")
async def delete_book(book_id: int, db: AsyncSession = Depends(get_database)):
db_book = await db.get(Book, book_id)
if not db_book:
raise HTTPException(status_code=404, detail="查无此书")
await db.delete(db_book) # 删除对象
return {"msg": "删除图书成功"}
实战
下面是教程所附项目后端设计说明文档,个人觉得非常优雅规范!因此附在此笔记中供日后温习。
AI掘金头条新闻系统 (Toutiao News)
一个基于 FastAPI 和 SQLAlchemy 构建的现代化新闻系统,支持用户注册登录、新闻浏览、收藏和历史记录等功能。
1-1 项目概述
这是一个仿今日头条的新闻系统后端API服务,采用异步Python框架FastAPI开发,使用MySQL作为数据库存储,通过SQLAlchemy ORM进行数据访问。系统提供完整的用户管理、新闻浏览、收藏和历史记录功能。
1-2 技术栈
- 后端框架: FastAPI
- 数据库: MySQL
- ORM: SQLAlchemy (异步)
- 数据库驱动: aiomysql
- 密码加密: passlib + bcrypt
- 缓存系统: Redis
- 异步支持: Python asyncio
1-3 项目结构
toutiao_backend/ # 项目根目录
├── crud/ # 数据访问层(CRUD操作)
│ ├── favorite.py # 收藏相关数据库操作
│ ├── history.py # 历史记录相关数据库操作
│ ├── news.py # 新闻相关数据库操作
│ └── users.py # 用户相关数据库操作
│
├── models/ # 数据模型定义
│ ├── favorite.py # 收藏数据模型
│ ├── history.py # 历史记录数据模型
│ ├── news.py # 新闻数据模型
│ └── users.py # 用户数据模型
│
├── routers/ # API路由定义
│ ├── favorite.py # 收藏相关API路由
│ ├── history.py # 历史记录相关API路由
│ ├── news.py # 新闻相关API路由
│ └── users.py # 用户相关API路由
│
├── schemas/ # 数据验证模型(Pydantic模型)
│ ├── favorite.py # 收藏数据验证模型
│ ├── history.py # 历史记录数据验证模型
│ ├── news.py # 新闻数据验证模型
│ └── users.py # 用户数据验证模型
│
├── utils/ # 工具函数目录
│
├── config/ # 配置相关
│ ├── db_conf.py # 数据库配置文件
│ ├── cache_conf.py # Redis缓存配置
│
├── main.py # 应用入口文件
└── test_main.http # HTTP接口测试文件
1-4 功能模块
\1. 用户管理模块
- 用户注册
- 用户登录
- 用户信息获取
- 用户信息更新
- 用户密码修改
\2. 新闻模块
- 新闻分类获取
- 新闻列表获取(支持分页和分类筛选)
- 新闻详情获取
- 浏览量统计
\3. 收藏模块
- 添加收藏
- 取消收藏
- 收藏列表获取
- 清空所有收藏
- 检查收藏状态
\4. 浏览历史模块
- 添加浏览记录
- 浏览历史列表获取
- 删除单条浏览记录
- 清空浏览历史
\5. 缓存模块
- 新闻详情缓存
- 新闻列表缓存
- 分类数据缓存
- 用户历史记录缓存
1-5 数据库设计
主要数据表
- 用户表 (user)
-
- 用户基本信息存储
- 包含用户名、密码(加密)、昵称、头像等字段
- 用户令牌表 (user_token)
-
- 用户认证令牌管理
- 支持令牌过期机制
- 新闻分类表 (news_category)
-
- 新闻分类信息
- 新闻表 (news)
-
- 新闻内容存储
- 包含标题、内容、作者、浏览量等字段
- 收藏表 (favorite)
-
- 用户收藏记录
- 关联用户和新闻
- 浏览历史表 (history)
-
- 用户浏览历史记录
- 关联用户和新闻
1-6 缓存设计
缓存策略
系统采用 Redis 作为缓存层,对高频访问的数据进行缓存,以提升系统性能和响应速度。
缓存数据类型
- 新闻详情缓存
-
- 缓存键:
news:detail:{news_id} - 过期时间: 1小时
- 提升新闻详情页面访问速度
- 缓存键:
- 新闻列表缓存
-
- 缓存键:
news:list:{category_id}:{page}:{size} - 过期时间: 30分钟
- 减少首页和分类页面的数据库查询压力
- 缓存键:
- 分类数据缓存
-
- 缓存键:
news:categories - 过期时间: 2小时
- 加速导航栏分类数据加载
- 缓存键:
- 用户历史记录缓存
-
- 缓存键:
history:list:{user_id} - 过期时间: 1小时
- 提高用户历史记录访问性能
- 缓存键:
缓存更新机制
- 数据更新时自动清除相关缓存
- 采用缓存失效而非主动更新策略
- 支持批量清除特定模式的缓存
缓存配置
在 cache_conf.py 中配置 Redis 连接信息:
python
REDIS_HOST = "localhost"
REDIS_PORT = 6379
REDIS_DB = 0
1-7 API 接口说明
用户相关接口
| 接口 | 方法 | 说明 |
|---|---|---|
/api/user/register |
POST | 用户注册 |
/api/user/login |
POST | 用户登录 |
/api/user/info |
GET | 获取用户信息 |
/api/user/update |
PUT | 更新用户信息 |
/api/user/password |
PUT | 修改用户密码 |
新闻相关接口
| 接口 | 方法 | 说明 |
|---|---|---|
/api/news/categories |
GET | 获取新闻分类列表 |
/api/news/list |
GET | 获取新闻列表 |
/api/news/detail |
GET | 获取新闻详情 |
收藏相关接口
| 接口 | 方法 | 说明 |
|---|---|---|
/api/favorite/check |
GET | 检查新闻收藏状态 |
/api/favorite/add |
POST | 添加收藏 |
/api/favorite/remove |
DELETE | 取消收藏 |
/api/favorite/list |
GET | 获取收藏列表 |
/api/favorite/clear |
DELETE | 清空所有收藏 |
浏览历史相关接口
| 接口 | 方法 | 说明 |
|---|---|---|
/api/history/add |
POST | 添加浏览记录 |
/api/history/list |
GET | 获取浏览历史列表 |
/api/history/delete/{history_id} |
DELETE | 删除单条浏览记录 |
/api/history/clear |
DELETE | 清空浏览历史 |
1-8 认证机制
系统使用基于令牌(Token)的认证机制:
- 用户登录成功后返回访问令牌
- 需要认证的接口在请求头中添加
Authorization: token值 - 令牌有效期为7天
1-9 错误处理
系统提供统一的错误处理机制:
- 用户认证失败返回 401 状态码
- 资源不存在返回 404 状态码
- 服务器内部错误返回 500 状态码
1-10 开发规范
- 使用异步数据库操作
- 所有密码均加密存储
- 接口返回统一的 JSON 格式
- 详细的接口文档和示例
- 缓存操作封装成独立函数便于调用
1-11 性能优化
- 使用 Redis 缓存热点数据
- 异步数据库操作提升并发性能
- 合理的数据库索引设计
- 连接池管理减少连接开销
模块化路由、数据库和 ORM 配置
python
# 模块化路由
# 1. 在routers文件夹中对应路由文件中创建APIRouter实例
# 2. 在main.py中添加app.include_router()
# /routers/news.py
from fastapi import APIRouter
# 创建 APIRouter 实例
# prefix 路由前缀(API 接口规范文档)
# tags 分组 标签
router = APIRouter(prefix="/api/news", tags=["news"])
@router.get("/categories")
async def get_categories(skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db)):
categories = await news.get_categories(db, skip, limit)
return {
"code": 200,
"message": "获取新闻分类成功",
"data": categories
}
# main.py
from fastapi import FastAPI
from routers import news, users
app = FastAPI()
@app.get("/")
async def root():
return {"message": "Hello World"}
# 挂载路由/注册路由
app.include_router(news.router)
app.include_router(users.router)
# 数据库和ORM配置
# 1. 安装SQLAlchemy pip install "sqlalchemy[asyncio]" aiomysql
# 2. ORM配置,放config文件夹中的db_conf.py中
from sqlalchemy.ext.asyncio import async_sessionmaker, AsyncSession, create_async_engine
# 数据库URL
ASYNC_DATABASE_URL = "mysql+aiomysql://root:123456@localhost:3306/news_app?charset=utf8mb4"
# 创建异步引擎
async_engine = create_async_engine(
ASYNC_DATABASE_URL,
echo=True, # 可选:输出SQL⽇志
pool_size=10, # 设置连接池中保持的持久连接数
max_overflow=20 # 设置连接池允许创建的额外连接数
)
# 创建异步会话⼯⼚
AsyncSessionLocal = async_sessionmaker(
bind=async_engine,
class_=AsyncSession,
expire_on_commit=False
)
# 依赖项,⽤于获取数据库会话
async def get_db():
async with AsyncSessionLocal() as session:
try:
yield session
await session.commit()
except Exception:
await session.rollback()
raise
finally:
await session.close()
接口实现完整流程
python
# /routers/news.py
from fastapi import APIRouter, Depends, Query, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from config.db_conf import get_db
from crud import news
# 创建 APIRouter 实例
# prefix 路由前缀(API 接口规范文档)
# tags 分组 标签
router = APIRouter(prefix="/api/news", tags=["news"])
# 接口实现流程
# 1. 模块化路由 → API 接口规范文档
# 2. 定义模型类 → 数据库表(数据库设计文档)
# 3. 在 crud 文件夹里面创建文件,封装操作数据库的方法
# 4. 在路由处理函数里面调用 crud 封装好的方法,响应结果
@router.get("/categories")
async def get_categories(skip: int = 0, limit: int = 100, db: AsyncSession = Depends(get_db)):
# 先获取数据库里面新闻分类数据 → 先定义模型类 → 封装查询数据的方法
categories = await news.get_categories(db, skip, limit)
return {
"code": 200,
"message": "获取新闻分类成功",
"data": categories
}
# main.py
from fastapi import FastAPI
from routers import news, users
from fastapi.middleware.cors import CORSMiddleware
from utils.exception_handlers import register_exception_handlers
app = FastAPI()
# 注册异常处理器
register_exception_handlers(app)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # 允许的源,开发阶段允许所有源,生产环境需要指定源
allow_credentials=True, # 允许携带cookie
allow_methods=["*"], # 允许的请求方法
allow_headers=["*"], # 允许的请求头
)
@app.get("/")
async def root():
return {"message": "Hello World"}
# 挂载路由/注册路由
app.include_router(news.router)
app.include_router(users.router)
# /models/news.py
from datetime import datetime
from typing import Optional
from sqlalchemy import DateTime, Index, Text, ForeignKey
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column
from sqlalchemy import Integer, String
class Base(DeclarativeBase):
created_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now,
comment="创建时间"
)
updated_at: Mapped[datetime] = mapped_column(
DateTime,
default=datetime.now,
onupdate=datetime.now,
comment="更新时间"
)
class Category(Base):
__tablename__ = "news_category"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True, comment="分类ID")
name: Mapped[str] = mapped_column(String(50), unique=True, nullable=False, comment="分类名称")
sort_order: Mapped[int] = mapped_column(Integer, default=0, nullable=False, comment="排序")
def __repr__(self):
return f"<Category(id={self.id}, name={self.name}, sort_order={self.sort_order})>"
# /crud/news.py
from sqlalchemy import select, func, update
from sqlalchemy.ext.asyncio import AsyncSession
from models.news import Category, News
async def get_categories(db: AsyncSession, skip: int = 0, limit: int = 100):
stmt = select(Category).offset(skip).limit(limit)
result = await db.execute(stmt)
return result.scalars().all()
其他中间件的用法就不再写了,换汤不换药,本笔记用于快速熟悉 FastAPI 架构开发,之后复习到其他内容再总结用法