创建表
定义表
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 一样