1. 主键
在数据库中,主键都是设置成非空的。不过在SQLModel中,主键需要设置成可空的,如:
1
| id: int | None = Field(default=None, primary_key=True)
|
这是因为这里的id
是由数据库自动生成的,而非在Python代码中。因此在创建一个实例的时候,一般都不会设置id
,直到持久化到数据库中。因此,需要设置成可空字段,以免数据校验出错。
2. 连接数据库
可以通过create_engine创建一个数据库连接:
1 2 3 4
| sqlite_file_name = "database.db" sqlite_url = f"sqlite:///{sqlite_file_name}"
engine = create_engine(sqlite_url, echo=True)
|
创建一个异步的数据库连接(需要安装aiosqlite包):
1 2 3 4 5 6 7 8 9
| from sqlalchemy.ext.asyncio import create_async_engine from sqlmodel.ext.asyncio.session import AsyncSession
sqlite_file_name = "database.db" sqlite_url = f"sqlite+aiosqlite:///{sqlite_file_name}"
engine = create_async_engine(sqlite_url) async with AsyncSession(engine) as session:
|
3. 建表
定义完模型之后,可以使用SQLModel.metadata.create_all(engine)
来创建数据库表,每一个继承自SQLModel
并配置了table = True
的类,都会在metadata
属性中进行注册。因此,可以通过create_all创建所有表。
也正是这种注册关系,如果模型定义在另外的.py文件中时,需要在调用create_all前import已经定义好的模型。
注意:不建议在真实项目中使用create_all来创建数据库结构,SQLModel还没法很精确的控制类型、字段长度、字段顺序,复杂索引等问题,在需要进行数据库调优的场合中,建议同步维护对应的SQL文件,并保持模型定义的简洁性。
4. 数据插入
注意如下程序段:
1 2 3 4 5 6
| with Session(engine) as session: session.add(hero_1) print("Hero 1:", hero_1) session.commit() print("Hero 1:", hero_1) print("Hero 1 ID:", hero_1.id)
|
- 第一个print,这个时候还未存入数据库,所以ID为None
- 第二个print,已经提交到数据库,SQLAlchemy后台将该对象标定为过期。因为id,updatetime之类的数据可能在数据库中发生改变,因而目前内存中这个对象中的数据不是最新的。
- 第三个print,这时需要该对象的一个属性的最新值,SQLAlchemy后台将会刷新载入该对象对应的数据库记录,在内存中形成最新数据版本。
- 也可以用 session.refresh(object) 语句来显式刷新数据。
5. 数据查询
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| with Session(engine) as session: statement = select(Hero) results = session.exec(statement) for hero in results: print(hero)
statement = select(Hero).where(Hero.name == "Deadpond")
statement = select(Hero).where(Hero.name == "Deadpond").where(Hero.age == 48)
statement = select(Hero).where(Hero.name != "Deadpond")
statement = select(Hero).where(Hero.age > 35)
statement = select(Hero).where(Hero.age >= 35)
statement = select(Hero).where(Hero.age >= 35).where(Hero.age < 40)
statement = select(Hero).where(Hero.age >= 35, Hero.age < 40)
statement = select(Hero).where(or_(Hero.age <= 35, Hero.age > 90))
statement = select(Hero).offset(3).limit(3)
hero = session.get(Hero, 1)
hero = results.first()
hero = results.one()
heroes = results.all()
|