使用SQLModel和FastAPI实现英雄数据更新功能详解
项目概述
本文将深入讲解如何使用SQLModel和FastAPI构建一个支持CRUD操作的RESTful API,重点聚焦在数据更新功能的实现。SQLModel是一个强大的Python库,它结合了SQLAlchemy和Pydantic的优点,能够简化数据库模型的定义和操作。
核心模型设计
英雄基础模型
首先定义了HeroBase
模型作为所有英雄相关模型的基类,包含三个字段:
name
: 英雄名称,设置为索引字段secret_name
: 英雄秘密身份age
: 英雄年龄,可选字段,也设置为索引
class HeroBase(SQLModel):
name: str = Field(index=True)
secret_name: str
age: Optional[int] = Field(default=None, index=True)
数据库模型
Hero
模型继承自HeroBase
并添加了数据库特有字段:
id
: 主键,自动生成hashed_password
: 存储加密后的密码
class Hero(HeroBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
hashed_password: str = Field()
数据传输模型
系统设计了多个数据传输模型以适应不同场景:
HeroCreate
: 用于创建英雄,包含原始密码字段HeroPublic
: 用于返回给客户端的数据,不包含敏感信息HeroUpdate
: 专门用于更新操作,所有字段都是可选的
数据库配置
使用SQLite作为数据库,配置了以下参数:
check_same_thread=False
: 允许多线程访问echo=True
: 输出SQL语句,方便调试
sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"
connect_args = {"check_same_thread": False}
engine = create_engine(sqlite_url, echo=True, connect_args=connect_args)
API端点实现
创建英雄
POST /heroes/
端点接收HeroCreate
数据,处理密码加密后存入数据库:
@app.post("/heroes/", response_model=HeroPublic)
def create_hero(hero: HeroCreate):
hashed_password = hash_password(hero.password)
with Session(engine) as session:
extra_data = {"hashed_password": hashed_password}
db_hero = Hero.model_validate(hero, update=extra_data)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero
查询英雄
实现了两个查询端点:
GET /heroes/
: 分页查询所有英雄GET /heroes/{hero_id}
: 查询单个英雄详情
更新英雄
PATCH /heroes/{hero_id}
端点实现了部分更新功能,这是本文的重点:
@app.patch("/heroes/{hero_id}", response_model=HeroPublic)
def update_hero(hero_id: int, hero: HeroUpdate):
with Session(engine) as session:
db_hero = session.get(Hero, hero_id)
if not db_hero:
raise HTTPException(status_code=404, detail="Hero not found")
hero_data = hero.model_dump(exclude_unset=True)
extra_data = {}
if "password" in hero_data:
password = hero_data["password"]
hashed_password = hash_password(password)
extra_data["hashed_password"] = hashed_password
db_hero.sqlmodel_update(hero_data, update=extra_data)
session.add(db_hero)
session.commit()
session.refresh(db_hero)
return db_hero
更新功能详解
部分更新实现原理
- 模型设计:
HeroUpdate
模型中所有字段都是可选的,这允许客户端只发送需要更新的字段 - 数据处理:使用
model_dump(exclude_unset=True)
只获取客户端实际设置的字段 - 密码处理:如果包含密码字段,会单独处理加密逻辑
- 更新操作:使用
sqlmodel_update
方法智能更新模型字段
安全考虑
- 密码字段不会直接存储,而是经过哈希处理
- 更新操作使用PATCH而非PUT,符合RESTful最佳实践
- 返回的数据模型
HeroPublic
不包含敏感信息
最佳实践建议
- 密码处理:示例中使用了简单的哈希函数,实际项目中应使用专业库如passlib
- 错误处理:对不存在的资源返回404状态码
- 分页查询:GET端点实现了基本的offset/limit分页
- 类型安全:充分利用Python类型提示提高代码可靠性
总结
通过这个示例,我们学习了如何使用SQLModel和FastAPI构建一个完整的CRUD API,特别是实现了符合RESTful规范的部分更新功能。SQLModel的强大之处在于它简化了数据库操作,同时保持了类型安全和代码简洁性。这种模式可以扩展到更复杂的业务场景中。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考