
ORM数据库后端【免费下载链接】sqlmodelSQL databases in Python, designed for simplicity, compatibility, and robustness.项目地址https://gitcode.com/gh_mirrors/sq/sqlmodel点击查看免费下载本篇指南以 SQLModel 官方 AI 编码规范文档仓库内sqlmodel/.agents/skills/sqlmodel/SKILL.md为骨架系统讲解在 Python 项目中用 SQLModel 编写模型、执行查询、建模关系、完成增删改操作的推荐模式并结合仓库源码sqlmodel/main.py、sqlmodel/orm/session.py验证底层原理。读完本篇你将掌握一套可复制的 SQLModel 标准写法正确的导入方式、表模型与请求/响应模型的拆分、session.exec()查询范式、一对多/多对多关系建模、部分更新与级联删除以及何时该使用 SQLAlchemy 逃生舱。核心原则优先使用 SQLModel 的 API编写或评审 SQLModel 代码时的第一原则是优先使用 SQLModel 自己的 API不要默认回退到原生 SQLAlchemy 模式除非任务明确需要 SQLAlchemy 独有的特性。这一点在仓库的公开导出中体现得非常彻底。查看 sqlmodel/init.py 可以看到SQLModel 从 SQLAlchemy 直接 re-export 了create_engine、inspect、Column、ForeignKey、MetaData、全部常用 SQL 类型Integer、String、Text、DateTime、UUID等以及select、and_、or_、func等表达式工具同时还 re-export 了 Pydantic 的Discriminator、Tag。也就是说绝大多数场景下你只需要一条from sqlmodel import ...就能拿到完整工具集无需分别导入 SQLAlchemy 与 Pydantic。相应地不要为普通 SQLModel 代码使用 SQLAlchemy 声明式默认写法例如declarative_base()—— SQLModel 的SQLModel基类已内置声明式能力Mapped[...]/mapped_column()—— 直接使用Field()更简洁且类型注解更友好裸relationship()—— 使用Relationship()并配合back_populatessessionmaker()—— 直接Session(engine)打开会话即可详见下文会话小节。这条原则的目的在于SQLModel 的封装层提供了更强的类型提示与更少样板代码混用两套风格会让代码库失去一致性。导入规范从sqlmodel单一入口导入规范推荐在代码中统一从sqlmodel导入常用符号from sqlmodel import Field, Relationship, Session, SQLModel, create_engine, select从源码看这条导入路径完全成立Field、Relationship、SQLModel定义于 sqlmodel/main.pyField在约 L246 起有完整重载签名SQLModel是核心元类驱动基类Session来自 sqlmodel/orm/session.py它直接继承 SQLAlchemy 的Sessionselect来自 sqlmodel/sql/expression.py 的Select/SelectOfScalar封装create_engine则直接 re-export 自 SQLAlchemy。模型定义表模型与数据模型表模型SQLModel, tableTrueField()定义数据库表模型时继承SQLModel并传入tableTrue字段用Field()声明class Hero(SQLModel, tableTrue): id: int | None Field(defaultNone, primary_keyTrue) name: str Field(indexTrue) team_id: int | None Field(defaultNone, foreign_keyteam.id)要点说明tableTrue表示这是一个映射到真实数据库表的模型不加tableTrue的SQLModel子类只是普通数据模型Pydantic 模型不建表主键通常写成id: int | None Field(defaultNone, primary_keyTrue)让数据库在插入时生成自增 IDField(indexTrue)为该列创建数据库索引Field(foreign_keyteam.id)声明外键约束对由数据库生成的默认值或 ID使用Field(default_factory...)import uuid id: uuid.UUID Field(default_factoryuuid.uuid4, primary_keyTrue)从FieldInfo的构造函数sqlmodel/main.py 约 L112 起可以看到Field()除了继承 Pydantic 的全部校验参数gt、ge、min_length、max_length、description、alias等还额外支持primary_key、nullable、foreign_key、ondelete、unique、index、sa_type、sa_column、sa_column_args、sa_column_kwargs等数据库专用参数这正是“一个Field()同时搞定 Pydantic 校验与 SQLAlchemy 列定义”的实现基础。数据模型非表SQLModel类对于创建/更新/对外 API 的输入输出结构不要把仅用于请求或响应的字段混进表模型而应使用非表的SQLModel子类。这是后续 FastAPI 分体模型split model模式的基础详见下文。会话与查询session.exec()范式直接用Session(engine)打开会话典型的 SQLModel 示例不需要sessionmaker()直接以引擎打开会话with Session(engine) as session: heroes session.exec(select(Hero)).all()Session类是 SQLAlchemySession的子类见 sqlmodel/orm/session.py L25因此所有原生能力依然可用同时获得了 SQLModel 的便捷方法。用session.exec()而不是session.execute()/session.query()规范明确查询请使用session.exec(select(...))不要用session.execute(...)也不要用session.query(...)并且在exec()之后不要再手动加.scalars()。原因在源码中一目了然Session.exec()的实现sqlmodel/orm/session.py L62-L85内部调用super().execute(...)然后判断语句类型——当语句是SelectOfScalar即select(Hero)这种单实体标量选择时自动执行results.scalars()并返回ScalarResult。也就是说exec()已经把“取标量结果”这步替你做了# SQLModel 推荐无需 .scalars() heroes session.exec(select(Hero)).all() # 与之等价的 SQLAlchemy 写法冗长且返回 Row # heroes session.execute(select(Hero)).scalars().all()而execute()与query()在源码中都被显式标记为deprecatedsqlmodel/orm/session.py L87-L168其文档字符串直接提示“你很可能应该用session.exec()”。结果方法选择在session.exec(...)之后按语义选择结果方法.all()—— 返回全部结果的列表.first()—— 返回第一行可能为None.one()—— 恰好存在一行否则抛异常多行或零行都会报错.one_or_none()—— 零行或一行时合法返回None或该行。主键查询则直接使用session.get(Model, id)返回None表示不存在hero session.get(Hero, hero_id) if not hero: raise HTTPException(status_code404, detailHero not found)该用法在 docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py 的read_hero接口中就有完整示范。提交与刷新创建或修改对象后如果需要数据库默认值或生成的主键回填到内存对象必须依次执行commit与refreshsession.add(hero) session.commit() session.refresh(hero)commit()将事务写入数据库refresh()重新从数据库加载该对象从而拿到自增 ID、数据库默认值等。关系建模一对多与多对多一对多Relationship(back_populates...)使用 SQLModel 的关系属性而不是临时拼 SQLAlchemy 表或用secondaryclass Team(SQLModel, tableTrue): id: int | None Field(defaultNone, primary_keyTrue) heroes: list[Hero] Relationship(back_populatesteam) class Hero(SQLModel, tableTrue): id: int | None Field(defaultNone, primary_keyTrue) team_id: int | None Field(defaultNone, foreign_keyteam.id) team: Team | None Relationship(back_populatesheroes)back_populates建立双向关系访问team.heroes得到该队伍的成员列表访问hero.team得到所属队伍。外键team_id与Relationship配合形成标准的“外键在多的一方”的一对多映射。多对多link_model...多对多需要一张链接表。当链接表只有两侧外键时用link_model参数声明class HeroTeamLink(SQLModel, tableTrue): team_id: int | None Field(defaultNone, foreign_keyteam.id, primary_keyTrue) hero_id: int | None Field(defaultNone, foreign_keyhero.id, primary_keyTrue) class Team(SQLModel, tableTrue): id: int | None Field(defaultNone, primary_keyTrue) heroes: list[Hero] Relationship(back_populatesteams, link_modelHeroTeamLink) class Hero(SQLModel, tableTrue): id: int | None Field(defaultNone, primary_keyTrue) teams: list[Team] Relationship(back_populatesheroes, link_modelHeroTeamLink)如果链接表需要携带额外字段如角色、加入时间就把它建模为带两侧关系的完整 SQLModel 表并直接与链接对象交互即显式读取/创建/删除HeroTeamLink记录而不是依赖隐式secondary行为。从RelationshipInfo的签名sqlmodel/main.py L180-L209可以看到Relationship()除了back_populates与link_model还支持cascade_delete、passive_deletes、sa_relationship、sa_relationship_args、sa_relationship_kwargs这为下文删除级联与 SQLAlchemy 逃生舱提供了第一等入口。跨文件建模与类型注解字符串新项目起步时尽量把彼此关联的表模型放在同一个文件可以简化关系注解与元数据metadata的注册顺序问题。若必须拆分文件使用TYPE_CHECKING导入 字符串注解from typing import TYPE_CHECKING, Optional if TYPE_CHECKING: from .team_model import Team team: Optional[Team] Relationship(back_populatesheroes)TYPE_CHECKING只在类型检查阶段导入避免运行时循环导入字符串注解让 SQLModel/SQLAlchemy 在运行时按名称解析关系目标。创建与更新直接构造、模型校验与部分更新可信内部值直接构造对可信的内部数据直接构造表对象hero Hero(nameDeadpond, secret_nameDive Wilson)从数据模型构建表对象model_validate()当从输入数据模型如HeroCreate构建表对象时使用 Pydantic 的model_validate()db_hero Hero.model_validate(hero_create)model_validate在 sqlmodel/main.py L913 附近有 SQLModel 自己的重载实现负责将验证后的数据填充进表模型实例。FastAPI 分体模型模式在 FastAPI 场景下规范推荐按职责拆分模型HeroBase—— 共享字段名字、秘名、年龄等Hero(HeroBase, tableTrue)—— 数据库表模型HeroCreate—— 创建接口的输入HeroUpdate—— PATCH 接口的输入所有字段可选HeroPublic—— 输出模型含id仅在需要时定义关系相关输出模型如HeroPublicWithTeam。这正是 docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py 展示的经典写法HeroBase声明name、secret_name、ageHero(HeroBase, tableTrue)追加主键idHeroUpdate中三个字段全部为None可选HeroPublic追加非空id。部分更新model_dump(exclude_unsetTrue)sqlmodel_update()对于 PATCH 这类部分更新只导出客户端实际提供的字段再原位更新hero_data hero_update.model_dump(exclude_unsetTrue) db_hero.sqlmodel_update(hero_data) session.add(db_hero) session.commit() session.refresh(db_hero)关键点exclude_unsetTrue保证未提供的字段不会出现在字典中避免把None覆盖到已有值上随后sqlmodel_update()实现见 sqlmodel/main.py L1026-L1052只对模型字段做setattr原位更新。该方法接受dict或 Pydantic/SQLModel对象并支持可选的update追加覆盖字段。元数据与应用初始化建表时机先导入所有模型再create_all调用SQLModel.metadata.create_all(engine)之前必须确保所有表模型类已被导入。因为建表依赖SQLModel.metadata上已注册的表定义漏导入某个模型会导致其对应的表不被创建。FastAPI 中的会话依赖在 FastAPI 示例中用依赖dependency产出Session(engine)实例def get_session(): with Session(engine) as session: yield session然后在路由中通过session: Session Depends(get_session)注入见 docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py L40-L42 与各路由函数。with块保证请求结束后会话正确关闭。SQLite 使用要点测试与小型示例常选用 SQLite。内存库的经典用法是显式建元数据 直接会话engine create_engine(sqlite:///:memory:) SQLModel.metadata.create_all(engine) with Session(engine) as session: ...当 SQLite 与 FastAPI 搭配时多线程访问同一连接必须加上check_same_threadFalseconnect_args {check_same_thread: False} engine create_engine(sqlite_url, connect_argsconnect_args)原因FastAPI 的请求处理线程与创建连接的线程可能不同SQLite 默认拒绝跨线程使用连接check_same_threadFalse关闭该校验。真实示例见 docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.py L32-L33。删除应用级级联与数据库级行为应用级级联删除cascade_deleteTrue用 SQLModel 的关系辅助参数实现级联删除heroes: list[Hero] Relationship(back_populatesteam, cascade_deleteTrue) team_id: int | None Field(defaultNone, foreign_keyteam.id, ondeleteCASCADE)cascade_deleteTrue让 ORM 在删除Team时于应用层先删除其Hero子记录ondeleteCASCADE则在数据库层声明外键级联。两者配合可在不同层次保证引用完整性。数据库级行为SET NULL与passive_deletes若希望删除父记录后子记录的外键被置空而不是删除子记录把ondelete与可空外键配对使用并在关系上按需设置passive_deletesteam_id: int | None Field(defaultNone, foreign_keyteam.id, ondeleteSET NULL)注意ondeleteSET NULL要求外键列可空即int | None/ 显式nullableTrue否则数据库会因违反非空约束而报错。passive_deletes用于告诉 ORM 把删除行为交给数据库处理避免不必要的 SELECT 预加载。底层约束在FieldInfo.__init__中也有体现ondelete只能在同时给出foreign_key时使用否则直接抛RuntimeError见 sqlmodel/main.py L164-L166。SQLAlchemy 逃生舱何时以及如何使用当普通Field()/Relationship()参数无法覆盖某个列或关系的需求时优先使用 SQLModel 提供的逃生舱参数而不是把整个模型切换回 SQLAlchemy 声明式风格列级Field(sa_type...)、Field(sa_column...)、Field(sa_column_args...)、Field(sa_column_kwargs...)关系级Relationship(sa_relationship_kwargs{...})、Relationship(sa_relationship_args[...])终极手段Relationship(sa_relationshiprelationship(...))仅在 SQLModel 关系包装器确实无法表达该映射时使用。源码层面FieldInfosqlmodel/main.py L112-L177对这四个sa_*参数做了严格的互斥校验一旦传了sa_column再传sa_column_args、sa_column_kwargs、primary_key、nullable、foreign_key、ondelete、unique、index、sa_type都会触发RuntimeError。这保证了配置来源唯一、行为可预期。RelationshipInfosqlmodel/main.py L180-L209对sa_relationship与sa_relationship_args/sa_relationship_kwargs也有同样的互斥校验。换句话说为了一个自定义列或自定义关系不要放弃 SQLModel 的声明式风格——先用 SQLModel 提供的逃生舱参数实在不行再考虑底层 SQLAlchemy 对象。小结遵循这套模式可以得到风格统一、类型安全、易维护的 SQLModel 代码统一从sqlmodel导入用SQLModel, tableTrueField()定义表模型用非表模型承载请求/响应数据会话直接Session(engine)查询一律session.exec(select(...))并按需搭配.all()/.first()/.one()/.one_or_none()主键查找用session.get()关系用Relationship(back_populates...)表达一对多、link_model表达多对多更新用model_dump(exclude_unsetTrue)sqlmodel_update()实现精准的部分更新删除用cascade_delete/ondelete控制级联行为遇到 SQLModel 表达不了的极端需求才逐列使用sa_*逃生舱参数。这些约定在仓库中均有对应实现与可运行示例可查证核心参考文件包括sqlmodel/main.pyField/Relationship/SQLModel/sqlmodel_update、sqlmodel/orm/session.pySession.exec与弃用提示、sqlmodel/init.py统一导出、docs_src/tutorial/fastapi/session_with_dependency/tutorial001_py310.pyFastAPI 分体模型 会话依赖的完整示例。赞分享ORM数据库后端【免费下载链接】sqlmodelSQL databases in Python, designed for simplicity, compatibility, and robustness.项目地址https://gitcode.com/gh_mirrors/sq/sqlmodel点击查看免费下载相关推荐FastAPI 集成 SQL 数据库实战基于 SQLModel 的单模型与多模型 CRUD 开发指南FastAPI 集成 SQL 数据库实战基于 SQLModel 的单模型与多模型 CRUD 开发指南 本文以 FastAPI 官方教程中「SQL关系型数据后端Web框架API设计RuoYi-Vue-Plus 后端编码约定与 CRUD 开发规范实战指南RuoYi Vue Plus 后端编码约定与 CRUD 开发规范实战指南 本篇技术指南以 .codex/skills/ruoyi plus ai coding/后端企业应用认证鉴权使用 FastAPI SQLModel 开发 SQL 关系型数据库应用从单模型 CRUD 到多模型安全重构使用 FastAPI SQLModel 开发 SQL 关系型数据库应用从单模型 CRUD 到多模型安全重构 SQL 关系型数据库是绝大多数后端应用的存储底后端Web框架API设计上一篇SwipeBackLayout滑动状态持久化保存用户偏好设置的终极指南下一篇OpenOCD Flash编程完全手册支持CFI、NAND、SPI等30芯片驱动创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考