当前位置: 首页 > news >正文

Python SQLModel 简单使用

简介

Documentation: https://sqlmodel.tiangolo.com

Source Code: https://github.com/fastapi/sqlmodel

SQLModel 是 Python 中用于 SQL 数据库的操作工具,旨在实现简洁性、兼容性和健壮性。

SQLModel 是基于 SQLAlchemy 和 Pydantic 构建的。它由 FastAPI 的同一作者制作,旨在完美匹配需要使用 SQL 数据库的 FastAPI 应用程序。

SQLModel 基于 Python 的类型注解,并由 Pydantic 和 SQLAlchemy 提供支持。

其主要特性包括:

  • 易于编写:代码直观,编辑器支持良好,自动补全无处不在,减少调试时间。设计上易于使用和学习,节省阅读文档的时间。

  • 使用简单:提供合理的默认值,在底层完成大量工作,从而简化你编写的代码。

  • 兼容性强:专为与 FastAPI、Pydantic 和 SQLAlchemy 兼容而设计。

  • 可扩展性强:底层拥有 SQLAlchemy 和 Pydantic 的全部功能和灵活性。

  • 代码简洁:最大限度减少代码重复。一条类型注解即可完成多项任务,无需在 SQLAlchemy 和 Pydantic 中重复定义模型。

安装 SQLModel

由于 SQLModel 基于 Pydantic 和 SQLAlchemy 构建,因此它依赖这两个库。当你安装 SQLModel 时,它们将会被自动安装。

pip install sqlmodel -i https://mirrors.aliyun.com/pypi/simple/pip install pymysql -i https://mirrors.aliyun.com/pypi/simple/

创建数据模型

我们要做的第一件事是创建一个类来表示数据表中的数据。这种代表某些数据的类通常被称为模型(model)。

from typing import Optionalfrom sqlmodel import SQLModel, Fieldclass Users(SQLModel, table=True):__tablename__ = 'users'id: str = Field(primary_key=True, description="主键ID", max_length=64)name: str = Field(description="用户名", max_length=50)age: Optional[int] = Field(description="年龄", default=None)

table=True 会告诉 SQLModel 这是一个表模型,它应该表示 SQL 数据库中的一个表,而不仅仅是一个数据模型(就像其他常规的 Pydantic 类一样)。

创建引擎(Engine)

SQLModel 的引擎 engine(实际上它是一个 SQLAlchemy engine )是用来与数据库保持连接的。

创建引擎非常简单,只需使用一个数据库连接 URL 调用 create_engine() 即可:

from sqlmodel import create_engine# 连接到 MySQL 数据库
username = 'root'
password = '666666'
host = '127.0.0.1'  # 例如:'localhost' 或 '127.0.0.1'
port = '3306'  # 通常是 3306
database = 'my_sqlalchemy'
# 创建连接引擎
dbHost = f'mysql+pymysql://{username}:{password}@{host}:{port}/{database}'engine = create_engine(dbHost,echo=True,  # 是否打印SQLpool_size=10,  # 连接池的大小,指定同时在连接池中保持的数据库连接数,默认:5max_overflow=20,  # 超出连接池大小的连接数,超过这个数量的连接将被丢弃,默认: 5
)

通常情况下,你的整个应用程序中应该只创建一个引擎对象,并在各处重复使用它。

你可以在 SQLAlchemy 官方文档 中了解更多关于它所支持的各种数据库(同时也是 SQLModel 所支持的数据库)的详细信息。

SQLModel 为其 create_engine() 函数提供了自己的定义。它与 SQLAlchemy 的 create_engine() 是相同的,只是默认设置了 future=True 参数(这意味着它使用了 SQLAlchemy 最新版本,即 1.4 和未来的 2.0 所采用的风格)。

创建会话 Session

from sqlmodel import Session# 创建Session会话
session = Session(engine)

Session 以一个引擎(engine)作为参数,并在其底层使用该引擎。

添加数据

from data_model.users import Users
from mysql_client import sessionuser1 = Users(id="1", name="tom")
user2 = Users(id="2", name="jetty", age=18)
user3 = Users(id="3", name="tonny", age=22)session.add(user1)
session.add(user2)
session.add(user3)session.commit()

使用 with 语句块创建Session

from sqlmodel import Sessionfrom data_model.users import Users
from mysql_client import engineuser1 = Users(id="1", name="tom")
user2 = Users(id="2", name="jetty", age=18)
user3 = Users(id="3", name="tonny", age=22)with Session(engine) as session:session.add(user1)session.add(user2)session.add(user3)session.commit()

使用 with 语句块后,会在进入 with 块时自动创建会话,并将其赋值给变量 session,而在 with 块执行完毕后,会话会自动关闭。

查询数据

select语句

def select_all():with Session(engine) as session:statement = select(Users) # SQLModel的select语句

statement = select(Users) 相当于SQL语句:select id, name, age from users

执行该语句

现在我们已经有了 select 语句,可以使用会话(session)来执行它:

def select_all():with Session(engine) as session:statement = select(Users) # SQLModel的select语句result = session.exec(statement) # 执行

遍历查询结果

results 对象是一个可迭代对象,可以用来逐行遍历查询结果中的每一条记录。

现在我们可以将它放入一个 for 循环中,逐个打印出信息:

def select_all():with Session(engine) as session:statement = select(Users) # SQLModel的select语句result = session.exec(statement) # 执行for user in result:print(user)

完整代码:

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import enginedef select_all():with Session(engine) as session:statement = select(Users) # SQLModel的select语句result = session.exec(statement) # 执行for user in result:print(user)if __name__ == '__main__':select_all()

运行结果:

2025-06-21 22:50:10,074 INFO sqlalchemy.engine.Engine SELECT DATABASE()
2025-06-21 22:50:10,074 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:50:10,075 INFO sqlalchemy.engine.Engine SELECT @@sql_mode
2025-06-21 22:50:10,075 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:50:10,076 INFO sqlalchemy.engine.Engine SELECT @@lower_case_table_names
2025-06-21 22:50:10,076 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:50:10,077 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2025-06-21 22:50:10,082 INFO sqlalchemy.engine.Engine SELECT users.id, users.name, users.age 
FROM users
2025-06-21 22:50:10,082 INFO sqlalchemy.engine.Engine [generated in 0.00028s] {}
name='tom' id='1' age=None
name='jetty' id='2' age=18
name='tonny' id='3' age=22
2025-06-21 22:50:10,084 INFO sqlalchemy.engine.Engine ROLLBACK

获取对象列表

使用 result.all(),它可以返回包含所有对象的列表:

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import enginedef select_all():with Session(engine) as session:statement = select(Users) # SQLModel的select语句result = session.exec(statement) # 执行users = result.all() # 获取list对象print(users)if __name__ == '__main__':select_all()

运行结果:

2025-06-21 22:54:35,797 INFO sqlalchemy.engine.Engine SELECT DATABASE()
2025-06-21 22:54:35,797 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:54:35,798 INFO sqlalchemy.engine.Engine SELECT @@sql_mode
2025-06-21 22:54:35,798 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:54:35,799 INFO sqlalchemy.engine.Engine SELECT @@lower_case_table_names
2025-06-21 22:54:35,799 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:54:35,799 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2025-06-21 22:54:35,801 INFO sqlalchemy.engine.Engine SELECT users.id, users.name, users.age 
FROM users
2025-06-21 22:54:35,802 INFO sqlalchemy.engine.Engine [generated in 0.00014s] {}
[Users(name='tom', id='1', age=None), Users(name='jetty', id='2', age=18), Users(name='tonny', id='3', age=22)]
2025-06-21 22:54:35,803 INFO sqlalchemy.engine.Engine ROLLBACK

简洁版本

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import enginedef select_all():with Session(engine) as session:users = session.exec(select(Users)).all()print(users)if __name__ == '__main__':select_all()

运行结果:

2025-06-21 22:57:54,214 INFO sqlalchemy.engine.Engine SELECT DATABASE()
2025-06-21 22:57:54,215 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:57:54,216 INFO sqlalchemy.engine.Engine SELECT @@sql_mode
2025-06-21 22:57:54,216 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:57:54,216 INFO sqlalchemy.engine.Engine SELECT @@lower_case_table_names
2025-06-21 22:57:54,216 INFO sqlalchemy.engine.Engine [raw sql] {}
2025-06-21 22:57:54,217 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2025-06-21 22:57:54,220 INFO sqlalchemy.engine.Engine SELECT users.id, users.name, users.age 
FROM users
2025-06-21 22:57:54,220 INFO sqlalchemy.engine.Engine [generated in 0.00019s] {}
[Users(name='tom', id='1', age=None), Users(name='jetty', id='2', age=18), Users(name='tonny', id='3', age=22)]
2025-06-21 22:57:54,222 INFO sqlalchemy.engine.Engine ROLLBACK

where 条件查询

使用 SQLModel 通过 WHERE 子句过滤行

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import enginedef select_user():with Session(engine) as session:stmt = select(Users).where(Users.name == 'tom')results = session.exec(stmt)for user in results:print(user)if __name__ == '__main__':select_user()

可以连续调用where子句。

stmt = select(Users).where(Users.name == 'tom').where(Users.age > 18)

where 条件操作符:<、>、==、>=、<= 和 != 都是用于比较的运算符。

使用 or_

使用 or_ 在 .where() 中组合多个表达式,要做到这一点,你可以导入 or_:

from sqlmodel import Field, Session, SQLModel, create_engine, or_, selectfrom sqlmodel import Session, select, or_from data_model.users import Users
from mysql_client import enginedef select_user():with Session(engine) as session:stmt = select(Users).where(or_(Users.age > 18, Users.age < 60))results = session.exec(stmt)for user in results:print(user)if __name__ == '__main__':select_user()

读取单行数据

.first() 方法

读取第一行数据

但假设我们并不关心所有的行,而只想要第一行数据。我们可以调用 .first() 方法来获取第一行数据

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import engineif __name__ == '__main__':with Session(engine) as session:stmt = select(Users).where(Users.age > 18)result = session.exec(stmt)user = result.first() # 读取第一行数据print(user)

查询为空的情况下返回:None

.one() 方法

精确匹配一行(Exactly One)

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import engineif __name__ == '__main__':with Session(engine) as session:stmt = select(Users).where(Users.name == 'tom')result = session.exec(stmt)user = result.one()print(user)

结果返回了多行数据,但又期望只匹配一行时使用 .one(),会引发错误:

Traceback (most recent call last):File "D:\17-SQLModel\project\SQLModel\05-读取单行数据-one方法.py", line 16, in <module>user = result.one()^^^^^^^^^^^^File "D:\Miniconda\miniconda3\envs\SQLModel\Lib\site-packages\sqlalchemy\engine\result.py", line 1815, in onereturn self._only_one_row(^^^^^^^^^^^^^^^^^^^File "D:\Miniconda\miniconda3\envs\SQLModel\Lib\site-packages\sqlalchemy\engine\result.py", line 813, in _only_one_rowraise exc.MultipleResultsFound(
sqlalchemy.exc.MultipleResultsFound: Multiple rows were found when exactly one was required

同样地,如果使用 .one() 却完全没有查询到任何行,它也会抛出一个错误:

Traceback (most recent call last):File "D:\17-SQLModel\project\SQLModel\05-读取单行数据-one方法.py", line 16, in <module>user = result.one()^^^^^^^^^^^^File "D:\Miniconda\miniconda3\envs\SQLModel\Lib\site-packages\sqlalchemy\engine\result.py", line 1815, in onereturn self._only_one_row(^^^^^^^^^^^^^^^^^^^File "D:\Miniconda\miniconda3\envs\SQLModel\Lib\site-packages\sqlalchemy\engine\result.py", line 760, in _only_one_rowraise exc.NoResultFound(
sqlalchemy.exc.NoResultFound: No row was found when one was required

简洁写法

当然,在大多数情况下,使用 .first() 和 .one() 时你可能也会倾向于用更简洁的形式来书写,通常是一行代码(或至少是一个完整的 Python 语句):

user = session.exec(select(Users).where(Users.name == "Deadpond")).one()

Select by Id with .where()

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import engineif __name__ == '__main__':with Session(engine) as session:user = session.exec(select(Users).where(Users.id == 1)).first()print(user)

Select by Id with .get()

由于通过主键的 Id 列选择单个行是一种常见操作,因此这里有一个快捷方式:

from sqlmodel import Sessionfrom data_model.users import Users
from mysql_client import enginewith Session(engine) as session:user = session.get(Users, 11)print(user)

数据查询为空的情况下返回: None

limit 和 offset

limit查询

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import enginewith Session(engine) as session:stmt = select(Users).limit(3) # 从结果集中获取前3条数据result = session.exec(stmt)users = result.all()print(users)

简洁写法:

users = session.exec(select(Users).limit(3)).all()

Offset and Limit

from sqlmodel import Session, selectfrom data_model.users import Users
from mysql_client import enginewith Session(engine) as session:stmt = select(Users).where(Users.age < 100).offset(0).limit(3).order_by(Users.id)users = session.exec(stmt).all()print(users)

修改/更新数据

from sqlmodel import Sessionfrom data_model.users import Users
from mysql_client import enginewith Session(engine) as session:user = session.get(Users, 1) # 根据ID查询user.age = 100 # 设置字段值session.add(user) # 添加session.commit() # 提交session.refresh(user) # 刷新数据print(user)  # 打印

运行结果:

2025-06-22 16:20:22,916 INFO sqlalchemy.engine.Engine BEGIN (implicit)
# 查询
2025-06-22 16:20:22,919 INFO sqlalchemy.engine.Engine SELECT users.id AS users_id, users.name AS users_name, users.age AS users_age 
FROM users 
WHERE users.id = %(pk_1)s
2025-06-22 16:20:22,920 INFO sqlalchemy.engine.Engine [generated in 0.00021s] {'pk_1': 1}
# 更新
2025-06-22 16:20:22,923 INFO sqlalchemy.engine.Engine UPDATE users SET age=%(age)s WHERE users.id = %(users_id)s
2025-06-22 16:20:22,923 INFO sqlalchemy.engine.Engine [generated in 0.00019s] {'age': 100, 'users_id': '1'}
2025-06-22 16:20:22,924 INFO sqlalchemy.engine.Engine COMMIT
2025-06-22 16:20:22,927 INFO sqlalchemy.engine.Engine BEGIN (implicit)
# 刷新
2025-06-22 16:20:22,928 INFO sqlalchemy.engine.Engine SELECT users.id, users.name, users.age 
FROM users 
WHERE users.id = %(pk_1)s
2025-06-22 16:20:22,929 INFO sqlalchemy.engine.Engine [generated in 0.00015s] {'pk_1': '1'}
name='tom' id='1' age=100
2025-06-22 16:20:22,929 INFO sqlalchemy.engine.Engine ROLLBACK

删除数据

from sqlmodel import Sessionfrom data_model.users import Users
from mysql_client import enginewith Session(engine) as session:user = session.get(Users, 1)if user:session.delete(user) # 删除session.commit()

join 表连接

看官方文档吧!

FastAPI整合SQLModel

SQLModel 最为出色的一个使用场景,也是它被创建的主要原因之一,就是与 FastAPI 结合使用。

FastAPI 是一个由 SQLModel 的作者所创建的 Python Web 框架,专门用于构建 Web API。FastAPI 同样是基于 Pydantic 构建的。

安装SQLModel

pip install sqlmodel -i https://mirrors.aliyun.com/pypi/simple/pip install pymysql -i https://mirrors.aliyun.com/pypi/simple/

创建数据模型

base_sql_model.py 数据模型基类

from datetime import datetimefrom sqlmodel import SQLModel, Fieldclass BaseSQLModel(SQLModel):id: str = Field(primary_key=True, description="主键ID", max_length=64)create_time: datetime = Field(description="创建时间", default_factory=datetime.now)update_time: datetime = Field(description="修改时间", default_factory=datetime.now)is_delete: int = Field(description="是否删除:0-未删除,1-已删除", max_length=1, default=0)

user_model.py 数据模型类

from typing import Optionalfrom sqlmodel import Fieldfrom apps.user.data_model.base_sql_model import BaseSQLModelclass User(BaseSQLModel, table=True):__tablename__ = 'user'username: str = Field(description="用户名", max_length=50)password: str = Field(description="密码", max_length=100)phone: Optional[int] = Field(description="手机号", default=0)status: int = Field(description="用户状态:0-可用,1-不可用", max_length=1, default=0)

创建引擎以及Session会话

mysql_clinet.py

from sqlmodel import create_engine, Sessionfrom config import app_settingsclass MySQLClient:username = app_settings.mysql.usernamepassword = app_settings.mysql.passwordhost = app_settings.mysql.host  # 例如:'localhost' 或 '127.0.0.1'port = app_settings.mysql.port  # 通常是 3306database = app_settings.mysql.database_namedbHost = f'mysql+pymysql://{username}:{password}@{host}:{port}/{database}'engine = create_engine(dbHost,echo=app_settings.mysql.echo_sql,  # 是否打印SQLpool_size=app_settings.mysql.pool_size,  # 连接池的大小,指定同时在连接池中保持的数据库连接数,默认:5max_overflow=app_settings.mysql.max_overflow,  # 超出连接池大小的连接数,超过这个数量的连接将被丢弃,默认: 5pool_timeout=app_settings.mysql.pool_timeout,pool_recycle=app_settings.mysql.pool_recycle,pool_pre_ping=app_settings.mysql.pool_pre_ping,)@classmethoddef get_db_session(cls,)-> Session:with Session(cls.engine) as session:yield session

FastAPI中使用SQLModel

user_router.py

users = APIRouter()@users.post("/register", response_model=Result, summary="用户注册")
async def register(user_register: UserRegister, user_service: UserService = Depends()):user_service.register(user_register)return Result(message="注册成功,请跳转到登录")

user_service.py

class UserService:def __init__(self,user_dao: UserDAO = Depends(),user_ext_info_dao: UserExtInfoDAO = Depends(),redis_client: RedisClient = Depends(get_redis_client),db_session: Session = Depends(MySQLClient.get_db_session),):self.user_dao = user_daoself.user_ext_info_dao = user_ext_info_daoself.redis_client = redis_clientself.db_session = db_sessiondef find_by_user_id(self, user_id)-> UserVo:"""根据用户ID查询"""user = self.user_dao.find_by_id(user_id)# 用户不存在if user is None:raise UserNotFoundException# 字典解包user_vo = UserVo(**user.__dict__)return user_vo

user_dao.py

class UserDAO:def __init__(self, db_session: Session = Depends(MySQLClient.get_db_session),):self.db_session = db_sessiondef find_by_id(self, user_id):return self.db_session.get(User, user_id)def find_user_by_username(self, username: str):

 

相关文章:

  • 《计算机网络:自顶向下方法(第8版)》Chapter 8 课后题
  • 链接脚本基础语法
  • 面试150 除自身以外数组的乘积
  • 今日推荐:data-engineer-handbook
  • 包教包会,ES6类class的基本入门
  • 本地编译LibreHardwareMonitor
  • 仕么是Transformer以及工作原理和架构
  • 人工智能、机器人最容易取哪些体力劳动和脑力劳动
  • MySQL学习(1)——基础库操作
  • C++智能指针编程实例
  • Redis-CPP 5大类型操作
  • C#Halcon从零开发_Day14_AOI缺陷检测策略1_Bolb分析+特征分析_饼干破损检测
  • Kotlin 中为什么没有静态变量和静态方法—不用static?
  • 鸿蒙 Column 组件指南:垂直布局核心技术与场景化实践
  • Pandas 数据清洗
  • 端侧调用云数据库获取业务数据
  • 【Datawhale组队学习202506】YOLO-Master task03 IOU总结
  • 从iPSC到成熟细胞,纳米生物材料如何当“向导”?
  • 【大模型微调】6.模型微调实测与格式转换导出
  • 核心概念解析:AI、数据挖掘、机器学习与深度学习的关系
  • 做ppt素材的网站/绍兴seo优化
  • 高端网站制作哪家好/做个公司网站大概多少钱
  • 有哪些网站可以做外贸/免费的网站推广软件下载
  • ui网站建设站评价/互联网宣传推广
  • c2c网站建设/网络服务提供者收集和使用个人信息应当符合的条件有
  • 网站制作软件工程师/镇江网页设计