1059 字
5 分钟
基础使用

创建表#

定义表#

from sqlmodel import Field, SQLModel, create_engine
class Hero(SQLModel, table=True):
id: int | None = Field(default=None, primary_key=True)
name: str
secret_name: str
age: int | None = None
WARNING

这里如果不填 table=True,那么他将只是数据模型,不会被转换为表模型

这里的 age 告诉 Pydantic,age 在验证的时候不是必须的,而且默认值为 None,而 id 被标记为主键,这里把 id 标记为 None 因为主键是必须得,但是他将由数据库生成,而不是由我们的代码生成,因此在创建实例的时候我们不会设置 id,直到我们把他保存到数据库中才会有值.如果我们不设置 default 值,那么在后续使数据验证的时候会带来一些问题.

自动迁移表#

sqlite_file_name = "database.db"
sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url, echo=True)
SQLModel.metadata.create_all(engine)

SQLModel 有一个 metadata 的属性,他是 MetaData 的一个实例,当我们继承 SQLModel 并配置 table=true,他都会在 metadata 中注册.调用 create_all 能创建所有在 metadata 中注册的表

创建会话#

到目前为止,我们只使用引擎来与数据库交互,引擎是我们的所有代码共享的单个对象,负责与数据库通信,处理链接,但是在使用 sqlmodel,将使用他之上的一个工具,也就是会话,我们为每个属于同一组的数据库操作创建一个新的 会话

def create_heroes():
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)
session = Session(engine)
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()
session.close()

上面的代码记得使用 close 清理资源哦~,但是这样很容易忘记,因此我们需要使用 with 来帮我们管理

def create_heroes():
hero_1 = Hero(name="Deadpond", secret_name="Dive Wilson")
hero_2 = Hero(name="Spider-Boy", secret_name="Pedro Parqueador")
hero_3 = Hero(name="Rusty-Man", secret_name="Tommy Sharp", age=48)
with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
session.commit()

刷新对象#

with Session(engine) as session:
session.add(hero_1)
session.add(hero_2)
session.add(hero_3)
print("After adding to the session")
print("Hero 1:", hero_1)
print("Hero 2:", hero_2)
print("Hero 3:", hero_3)
session.commit()
print("After committing the session")
print("Hero 1:", hero_1)
print("Hero 2:", hero_2)
print("Hero 3:", hero_3)

在这里,我们 commit 后,代码第二次打印的内容居然是空的!这是因为 sqlalchemy 把这些对象标记为过期,没有最新的版本,可以调用 session.refresh(hero_1) 来刷新对象

Select#

def select_heroes():
with Session(engine) as session:
statement = select(Hero)
result = session.exec(statement)
for hero in results:#一个可迭代对象
print(hero)

上面我们得到的 result 只是一个可迭代对象,为了获得完整的列表,我们可以使用.all() 方法

与 Sqlalchemy 的区别#

sqlalchemy 自己的 session 有一个 execute 方法,没有这里的 exec,而 sqlmodel 的 session 直接继承 sqlalchemy 的 session,并添加的额外的 exec,但是添加了一些技巧让他变的更方便,

例如,在 SQLAlchemy 中,您需要在此处添加 .scalars()

heroes = session.execute(select(Hero)).scalars().all()

但是,在选择多个内容时,您必须将其删除(我们稍后会看到)。

SQLModel 的 session.exec() 会为您处理此问题,因此您无需添加 .scalars()

这是 SQLAlchemy 目前无法提供的功能,因为常规的 session.execute() 支持其他几种用例,包括遗留的用例,因此它不能具有所有内部类型注释和技巧来支持此功能。

使用 where#

selece(Hero).where(name=='xyh')

通常使用 name=='xyh' 会返回 true or false,但是 SQLAlchemy 为模型类中的列/字段添加了一些魔力,使这些 Python 比较具有超能力。他会产生一种特殊类型的对象.当使用但是如果你取一个实例

some_hero = Hero(name="Deadpond", secret_name="Dive Wilson")

…并在比较中使用它

some_hero.name == "Deadpond"

…这将产生一个 Python 值

True

def select_heroes():
with Session(engine) as session:
statement = select(Hero).where(Hero.age >= 35, Hero.age < 40)
statement = select(Hero).where(or_(Hero.age <= 35, Hero.age > 90))
results = session.exec(statement)
for hero in results:
print(hero)

读取一行#

第一行或 None#

def select_heroes():
with Session(engine) as session:
statement = select(Hero).where(Hero.age < 25)
results = session.exec(statement)
hero = results.first()
print("Hero:", hero)

他会返回一个或 None

恰好等于一行#

def select_heroes():
with Session(engine) as session:
statement = select(Hero).where(Hero.name == "Deadpond")
results = session.exec(statement)
hero = results.one()
print("Hero:", hero)

可能存在我们需要确保查询恰好匹配 一行 的情况。

如果有多于一行,则意味着系统存在错误,我们应该终止并报错。

使用 .get() 按 ID 选择#

由于使用 主键 按其 Id 列选择单行是一个常见操作,因此有一个快捷方式

def select_heroes():
with Session(engine) as session:
hero = session.get(Hero, 1)
print("Hero:", hero)

这和 first 一样