SQLModel零基础教程(一)- 核心概念与单表CRUD

发布时间:2026/6/29 21:58:40
SQLModel零基础教程(一)- 核心概念与单表CRUD 这里写目录标题前言一、前置说明学习前必读1. SQLModel 核心优势2. 必备前置基础3. 环境安装4. 两大核心模型区分重中之重二、第一阶段基础入门核心概念 单表 CRUD阶段学习目标步骤 1四大核心组件概念拆解1.1 SQLModel基类1.2 Field双用途字段配置1.3 Engine数据库引擎1.4 Session数据库会话步骤 2定义数据库实体模型实操步骤 3创建数据库 Engine 引擎3.1 SQLite本地文件无需安装服务新手推荐3.2 MySQL线上项目常用步骤 4自动创建 / 删除数据表步骤 5Session 标准会话写法with 上下文步骤 6完整单表 CRUD 实战全量可运行代码步骤 7CRUD 核心方法详解三、阶段核心总结半天必背知识点四、新手高频避坑指南前言前面我们完整学完Pydantic v2掌握了数据校验、序列化、前后端驼峰适配等能力但实际后端开发中还需要对接数据库。传统方案是「SQLAlchemy 做 ORM Pydantic 做入参出参」两套模型重复定义字段、大量重复转换代码开发效率极低。而SQLModel由 FastAPI 作者 tiangolo 开发底层融合SQLAlchemy 2.x数据库 ORM Pydantic v2数据校验一套模型同时兼顾数据库表映射、接口入参校验、返回序列化完美打通之前学的 Pydantic 知识是 FastAPI 项目官方推荐 ORM 工具也是目前 Python 后端最简数据库方案。一、前置说明学习前必读1. SQLModel 核心优势一套模型两用带tableTrue映射数据库表不带仅做 DTO 校验省去两套类重复定义继承 Pydantic 全部能力自动类型校验、Field约束、序列化、model_dump、自定义校验器全部通用完全兼容 SQLAlchemy底层基于 SQLAlchemy 2.0支持原生 SQL、关联查询、事务、Alembic 迁移极简 API抛弃 SQLAlchemy 繁琐写法select()替代复杂 Query上手门槛极低完美适配 FastAPI入参、返回体、数据库实体无缝互通接口开发效率翻倍。2. 必备前置基础Python 3.9推荐 3.10/3.11熟练掌握Pydantic v2BaseModel、Field、model_dump、ValidationError基础 SQL 知识增删改查、主键、索引、非空约束可选FastAPI 基础本文不依赖仅基础数据库操作。3. 环境安装# 安装核心库自动携带pydantic、sqlalchemy依赖pipinstallsqlmodel-ihttps://mirrors.aliyun.com/pypi/simple/ --find-links https://download.pytorch.org/whl/torch_stable.html --prefer-binary# 如需mysql、postgresql额外驱动sqlite无需pipinstallpymysql psycopg2-binary4. 两大核心模型区分重中之重SQLModel 只有两类模型新手最容易混淆先分清再往下学模型写法作用是否生成数据库表适用场景class User(SQLModel, tableTrue)数据库实体表是映射真实数据表包含主键、索引、数据库约束class UserCreate(SQLModel)DTO 数据模型否接口新增入参、更新入参、返回脱敏实体仅做校验序列化核心原理tableTrue会将类注册到SQLModel.metadata执行create_all时自动建表无该参数仅为纯 Pydantic 校验模型不会生成任何数据表。二、第一阶段基础入门核心概念 单表 CRUD阶段学习目标掌握SQLModel、Field、Engine、Session四大核心组件学会定义数据库实体、字段基础约束主键、非空、索引、默认值掌握多数据库连接字符串SQLite/MySQL、引擎配置表自动创建与销毁Session 会话标准写法with 上下文自动释放完整单表 CRUD新增、批量新增、主键查询、条件查询、更新、删除捕获数据库校验异常理解 Pydantic 预校验优势。步骤 1四大核心组件概念拆解1.1 SQLModel基类所有数据库实体、DTO 模型的父类同时融合Pydantic 能力类型注解、数据校验、序列化model_dump()SQLAlchemy 能力表映射、字段列、查询语句、会话操作。1.2 Field双用途字段配置SQLModel 的Field同时支持数据库约束Pydantic 校验规则一套参数两用数据库参数primary_key、index、unique、nullable校验参数min_length、gt、max_length和 Pydantic 完全一致。1.3 Engine数据库引擎数据库全局连接管理器负责维护连接池、执行 SQL、统一数据库地址全局单例创建一次即可。常用参数echoTrue打印底层执行 SQL开发调试必备connect_args{check_same_thread: False}SQLite 多线程兼容。1.4 Session数据库会话所有增删改查操作必须通过 Session 完成代表一次数据库会话add()将实体加入待提交队列commit()提交事务写入数据库refresh()从数据库同步最新数据自增主键、数据库默认值rollback()出错回滚事务推荐with Session(engine)上下文自动关闭连接杜绝连接泄露。步骤 2定义数据库实体模型实操以用户表为例包含主键、字符串、数字、布尔、可选字段、索引约束fromsqlmodelimportSQLModel,FieldfromtypingimportOptionalfromdatetimeimportdatetime# 作用这会让 SQLModel 将这个类识别为一个数据库表的映射Model而不是一个普通的 Python 数据类DTO。# 结果SQLModel 会将这个模型的结构表名、字段、约束等注册到一个全局的元数据集合SQLModel.metadata中。# 数据库实体tableTrue 映射user表classUser(SQLModel,tableTrue):# 自增主键默认None数据库自动生成idid:Optional[int]Field(defaultNone,primary_keyTrue,description用户主键ID)# 用户名非空、唯一、建立索引长度3-16username:strField(nullableFalse,uniqueTrue,indexTrue,min_length3,max_length16)# 邮箱非空索引email:strField(nullableFalse,indexTrue)# 年龄可选范围0-120age:Optional[int]Field(defaultNone,ge0,le120)# 启用状态默认Trueis_active:boolField(defaultTrue)# 创建时间Python层自动填充当前时间create_time:datetimeField(default_factorydatetime.utcnow)关键说明主键必须Optional[int] Field(defaultNone, primary_keyTrue)新增时无需传 iddefault_factory用于动态默认值时间、列表替代静态default实例化时 Pydantic 会立刻校验字段非法参数直接抛ValidationError不用等到提交数据库报错。步骤 3创建数据库 Engine 引擎3.1 SQLite本地文件无需安装服务新手推荐fromsqlmodelimportcreate_engine# sqlite文件数据库SQLITE_URLsqlite:///./test.db# 初始化引擎echo打印SQLsqlite多线程兼容enginecreate_engine(SQLITE_URL,echoTrue,connect_args{check_same_thread:False})3.2 MySQL线上项目常用# 格式mysqlpymysql://账号:密码IP:端口/数据库名MYSQL_URLmysqlpymysql://root:123456127.0.0.1:3306/test_db?charsetutf8mb4enginecreate_engine(MYSQL_URL,echoFalse,pool_size10)步骤 4自动创建 / 删除数据表SQLModel.metadata会收集所有tableTrue的实体一键建表 / 删表fromsqlmodelimportSQLModel# 根据模型自动创建所有不存在的表defcreate_tables():SQLModel.metadata.create_all(bindengine)# 清空所有表开发调试慎用生产禁止defdrop_tables():SQLModel.metadata.drop_all(bindengine)if__name____main__:create_tables()生产环境禁止使用create_all做表更新后续高阶会讲 Alembic 迁移工具管理版本。步骤 5Session 标准会话写法with 上下文强制推荐with Session(engine)代码块结束自动关闭会话避免连接堆积fromsqlmodelimportSession# 基础会话模板withSession(engine)assession:# 所有CRUD操作写在这里pass步骤 6完整单表 CRUD 实战全量可运行代码整合上面所有组件一次性实现新增、查询、更新、删除全套操作fromsqlmodelimportSQLModel,Field,create_engine,Session,selectfromtypingimportOptionalfromdatetimeimportdatetimefrompydanticimportValidationError# 1. 定义数据库实体classUser(SQLModel,tableTrue):id:Optional[int]Field(defaultNone,primary_keyTrue)username:strField(nullableFalse,uniqueTrue,indexTrue,min_length3,max_length16)email:strField(nullableFalse,indexTrue)age:Optional[int]Field(defaultNone,ge0,le120)is_active:boolField(defaultTrue)create_time:datetimeField(default_factorydatetime.utcnow)# 2. 创建引擎SQLITE_URLsqlite:///./test.dbenginecreate_engine(SQLITE_URL,echoTrue,connect_args{check_same_thread:False})# 3. 创建数据表definit_db():# 含义连接到 engine 指定的数据库你的 SQLite 文件 test.db。# 逻辑检查数据库中是否存在这些表。如果不存在第一次运行时肯定不存在则根据模型中定义的字段和约束自动生成并执行 CREATE TABLE SQL 语句。SQLModel.metadata.create_all(bindengine)# ------------------- CRUD操作演示 -------------------if__name____main__:init_db()# 1. 新增单条数据 try:withSession(engine)assession:user1User(usernamezhangsan,emailzhangsanqq.com,age22)session.add(user1)session.commit()# refresh同步数据库生成的id、create_timesession.refresh(user1)print(新增用户,user1.model_dump())exceptValidationErrorase:print(数据校验失败,e.errors())# 2. 批量新增 withSession(engine)assession:user_list[User(usernamelisi,emaillisiqq.com,age25),User(usernamewangwu,emailwangwuqq.com,age18)]session.add_all(user_list)session.commit()# 3. 根据主键ID查询 get() withSession(engine)assession:usersession.get(User,1)ifuser:print(主键查询,user.model_dump())else:print(用户不存在)# 4. 全量查询 条件查询 select() withSession(engine)assession:# 查询所有用户all_userssession.exec(select(User)).all()print(全部用户,[u.model_dump()foruinall_users])# 条件查询年龄大于20激活用户stmtselect(User).where(User.age20,User.is_activeTrue)filter_userssession.exec(stmt).all()print(筛选用户,[u.model_dump()foruinfilter_users])# 模糊匹配用户名 likelike_stmtselect(User).where(User.username.like(%zhang%))like_usersession.exec(like_stmt).first()print(模糊查询,like_user)# 5. 更新数据 withSession(engine)assession:usersession.get(User,1)ifuser:user.age23user.emailnew_zhangsanqq.comsession.commit()session.refresh(user)print(更新后,user.model_dump())# 6. 删除数据 withSession(engine)assession:usersession.get(User,3)ifuser:session.delete(user)session.commit()print(删除成功)步骤 7CRUD 核心方法详解新增核心流程add()→commit()→refresh()add存入会话缓存未写入数据库commit提交事务持久化refresh从数据库拉取自增 id、默认时间否则实体 id 为 None。查询两类 APIsession.get(模型, 主键值)仅根据主键快速查询最简session.exec(select(模型))支持多条件、模糊、分页、排序复杂查询必备。更新逻辑必须先查询出实体直接修改属性再 commit不支持无查询直接更新高阶批量更新后续讲解。删除逻辑查询实体 →session.delete(实例)→ commit。三、阶段核心总结半天必背知识点SQLModel 两类模型区分tableTrue数据表无参数 DTO 校验模型四大基础组件SQLModel 基类、Field 双用途字段、Engine 连接引擎、Session 事务会话Field 同时支持数据库约束与 Pydantic 数据校验实例化提前拦截脏数据Engine 区分 SQLite/MySQL 连接地址开发开启echoTrue打印 SQL 调试SQLModel.metadata.create_all()一键生成全部数据表Session 强制使用with上下文自动释放连接单表标准 CRUD 流程add/add_all 新增、get/select 查询、修改属性更新、delete 删除新增完成必须refresh()同步数据库自增主键。四、新手高频避坑指南❌ 定义主键忘记Optional新增直接报错❌ 新增后不调用refresh()实体 id 永远为 None❌ 混用tableTrue实体做接口返回 DTO泄露密码等敏感字段❌ 不用 with 手动创建 Session忘记 close 导致数据库连接耗尽❌ 生产环境频繁调用drop_all清空业务数据✅ 开发阶段开启echoTrue查看底层 SQL 快速定位问题✅ 可变默认值时间、列表统一使用default_factory。