SqlAlchemy 2.0 中文文档(四)(2)

简介: SqlAlchemy 2.0 中文文档(四)

SqlAlchemy 2.0 中文文档(四)(1)https://developer.aliyun.com/article/1562994


创建引擎

Engine是一个能够为我们创建新数据库连接的工厂,它还将连接保留在连接池中以供快速重用。出于学习目的,我们通常使用 SQLite 内存数据库以方便起见:

>>> from sqlalchemy import create_engine
>>> engine = create_engine("sqlite://", echo=True)

提示

echo=True 参数表示连接发出的 SQL 将被记录到标准输出。

Engine的全面介绍始于建立连接 - 引擎。

发出 CREATE TABLE DDL

使用我们的表元数据和引擎,我们可以一次性在目标 SQLite 数据库中生成我们的模式,使用一种叫做MetaData.create_all()的方法:

>>> Base.metadata.create_all(engine)
BEGIN  (implicit)
PRAGMA  main.table_...info("user_account")
...
PRAGMA  main.table_...info("address")
...
CREATE  TABLE  user_account  (
  id  INTEGER  NOT  NULL,
  name  VARCHAR(30)  NOT  NULL,
  fullname  VARCHAR,
  PRIMARY  KEY  (id)
)
...
CREATE  TABLE  address  (
  id  INTEGER  NOT  NULL,
  email_address  VARCHAR  NOT  NULL,
  user_id  INTEGER  NOT  NULL,
  PRIMARY  KEY  (id),
  FOREIGN  KEY(user_id)  REFERENCES  user_account  (id)
)
...
COMMIT 

刚才我们编写的那段 Python 代码发生了很多事情。要完整了解表元数据的情况,请参阅使用数据库元数据中的教程。

创建对象并持久化

我们现在可以将数据插入到数据库中了。我们通过创建UserAddress类的实例来实现这一点,这些类已经通过声明映射过程自动创建了__init__()方法。然后,我们使用一个称为 Session 的对象将它们传递给数据库,该对象使用Engine与数据库进行交互。这里使用Session.add_all()方法一次添加多个对象,并且将使用Session.commit()方法刷新数据库中的任何待处理更改,然后提交当前的数据库事务,该事务始终在使用Session时处于进行中:

>>> from sqlalchemy.orm import Session
>>> with Session(engine) as session:
...     spongebob = User(
...         name="spongebob",
...         fullname="Spongebob Squarepants",
...         addresses=[Address(email_address="spongebob@sqlalchemy.org")],
...     )
...     sandy = User(
...         name="sandy",
...         fullname="Sandy Cheeks",
...         addresses=[
...             Address(email_address="sandy@sqlalchemy.org"),
...             Address(email_address="sandy@squirrelpower.org"),
...         ],
...     )
...     patrick = User(name="patrick", fullname="Patrick Star")
...
...     session.add_all([spongebob, sandy, patrick])
...
...     session.commit()
BEGIN  (implicit)
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)  RETURNING  id
[...]  ('spongebob',  'Spongebob Squarepants')
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)  RETURNING  id
[...]  ('sandy',  'Sandy Cheeks')
INSERT  INTO  user_account  (name,  fullname)  VALUES  (?,  ?)  RETURNING  id
[...]  ('patrick',  'Patrick Star')
INSERT  INTO  address  (email_address,  user_id)  VALUES  (?,  ?)  RETURNING  id
[...]  ('spongebob@sqlalchemy.org',  1)
INSERT  INTO  address  (email_address,  user_id)  VALUES  (?,  ?)  RETURNING  id
[...]  ('sandy@sqlalchemy.org',  2)
INSERT  INTO  address  (email_address,  user_id)  VALUES  (?,  ?)  RETURNING  id
[...]  ('sandy@squirrelpower.org',  2)
COMMIT 

提示

建议像上面那样使用 Python 的 with: 语句,即使用上下文管理器样式使用SessionSession 对象代表着活跃的数据库资源,所以当一系列操作完成时,确保关闭它是很好的。在下一节中,我们将保持Session处于打开状态,仅用于说明目的。

创建Session的基础知识请参考使用 ORM Session 执行,更多内容请参考使用 Session 的基础知识。

接下来,介绍了一些基本持久化操作的变体,请参阅使用 ORM 工作单元模式插入行。

简单的 SELECT

在数据库中有一些行时,这是发出 SELECT 语句以加载一些对象的最简单形式。要创建 SELECT 语句,我们使用select() 函数创建一个新的Select 对象,然后使用Session 调用它。查询 ORM 对象时经常有用的方法是Session.scalars() 方法,它将返回一个ScalarResult 对象,该对象将迭代我们选择的 ORM 对象:

>>> from sqlalchemy import select
>>> session = Session(engine)
>>> stmt = select(User).where(User.name.in_(["spongebob", "sandy"]))
>>> for user in session.scalars(stmt):
...     print(user)
BEGIN  (implicit)
SELECT  user_account.id,  user_account.name,  user_account.fullname
FROM  user_account
WHERE  user_account.name  IN  (?,  ?)
[...]  ('spongebob',  'sandy')
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')

上述查询还使用了Select.where() 方法添加 WHERE 条件,并且还使用了所有 SQLAlchemy 列对象的一部分的ColumnOperators.in_() 方法来使用 SQL IN 操作符。

如何选择对象和单独列的更多详细信息请参阅选择 ORM 实体和列。

使用 JOIN 的 SELECT

在 SQL 中,一次查询多个表是非常常见的,而 JOIN 关键字是实现这一目的的主要方法。Select 构造函数使用Select.join() 方法创建连接:

>>> stmt = (
...     select(Address)
...     .join(Address.user)
...     .where(User.name == "sandy")
...     .where(Address.email_address == "sandy@sqlalchemy.org")
... )
>>> sandy_address = session.scalars(stmt).one()
SELECT  address.id,  address.email_address,  address.user_id
FROM  address  JOIN  user_account  ON  user_account.id  =  address.user_id
WHERE  user_account.name  =  ?  AND  address.email_address  =  ?
[...]  ('sandy',  'sandy@sqlalchemy.org')
>>> sandy_address
Address(id=2, email_address='sandy@sqlalchemy.org')

上述查询示例说明了多个 WHERE 条件如何自动使用 AND 连接,并且展示了如何使用 SQLAlchemy 列对象创建“相等性”比较,该比较使用了重载的 Python 方法ColumnOperators.__eq__()来生成 SQL 条件对象。

以上概念的更多背景可在 WHERE 子句和显式 FROM 子句和 JOIN 处找到。

进行更改

Session 对象与我们的 ORM 映射类 UserAddress 一起,会自动跟踪对象的更改,这些更改会导致 SQL 语句在下次 Session 刷新时被发出。下面,我们更改了与“sandy”关联的一个电子邮件地址,并在发出 SELECT 以检索“patrick”的行之后,向“patrick”添加了一个新的电子邮件地址:

>>> stmt = select(User).where(User.name == "patrick")
>>> patrick = session.scalars(stmt).one()
SELECT  user_account.id,  user_account.name,  user_account.fullname
FROM  user_account
WHERE  user_account.name  =  ?
[...]  ('patrick',)
>>> patrick.addresses.append(Address(email_address="patrickstar@sqlalchemy.org"))
SELECT  address.id  AS  address_id,  address.email_address  AS  address_email_address,  address.user_id  AS  address_user_id
FROM  address
WHERE  ?  =  address.user_id
[...]  (3,)
>>> sandy_address.email_address = "sandy_cheeks@sqlalchemy.org"
>>> session.commit()
UPDATE  address  SET  email_address=?  WHERE  address.id  =  ?
[...]  ('sandy_cheeks@sqlalchemy.org',  2)
INSERT  INTO  address  (email_address,  user_id)  VALUES  (?,  ?)
[...]  ('patrickstar@sqlalchemy.org',  3)
COMMIT 

注意当我们访问patrick.addresses时,会发出一个 SELECT。这被称为延迟加载。有关使用更多或更少的 SQL 访问相关项目的不同方法的背景介绍,请参阅加载器策略。

有关使用 ORM 进行数据操作的详细说明,请参阅 ORM 数据操作。

一些删除操作

万物都有尽头,就像我们的一些数据库行一样 - 这里快速演示了两种不同形式的删除,根据特定用例的重要性而定。

首先,我们将从sandy用户中删除一个Address对象。当Session下次刷新时,这将导致该行被删除。这种行为是我们在映射中配置的,称为级联删除。我们可以使用 Session.get() 按主键获取到sandy对象,然后操作该对象:

>>> sandy = session.get(User, 2)
BEGIN  (implicit)
SELECT  user_account.id  AS  user_account_id,  user_account.name  AS  user_account_name,  user_account.fullname  AS  user_account_fullname
FROM  user_account
WHERE  user_account.id  =  ?
[...]  (2,)
>>> sandy.addresses.remove(sandy_address)
SELECT  address.id  AS  address_id,  address.email_address  AS  address_email_address,  address.user_id  AS  address_user_id
FROM  address
WHERE  ?  =  address.user_id
[...]  (2,) 

上面的最后一个 SELECT 是为了进行延迟加载 操作,以便加载sandy.addresses集合,以便我们可以删除sandy_address成员。还有其他方法可以执行这一系列操作,不会发出太多的 SQL。

我们可以选择发出针对到目前为止被更改的 DELETE SQL,而不提交事务,使用 Session.flush() 方法:

>>> session.flush()
DELETE  FROM  address  WHERE  address.id  =  ?
[...]  (2,) 

接下来,我们将完全删除“patrick”用户。对于对象的顶级删除,我们使用Session.delete()方法;这个方法实际上并不执行删除操作,而是设置对象在下一次刷新时将被删除。该操作还会根据我们配置的级联选项级联到相关对象,本例中是关联的Address对象:

>>> session.delete(patrick)
SELECT  user_account.id  AS  user_account_id,  user_account.name  AS  user_account_name,  user_account.fullname  AS  user_account_fullname
FROM  user_account
WHERE  user_account.id  =  ?
[...]  (3,)
SELECT  address.id  AS  address_id,  address.email_address  AS  address_email_address,  address.user_id  AS  address_user_id
FROM  address
WHERE  ?  =  address.user_id
[...]  (3,) 

在这种特殊情况下,Session.delete()方法发出了两个 SELECT 语句,即使它没有发出 DELETE,这可能看起来令人惊讶。这是因为当方法检查对象时,发现patrick对象已经过期,这是在我们上次调用Session.commit()时发生的,发出的 SQL 是为了从新事务重新加载行。这种过期是可选的,在正常使用中,我们通常会在不适用的情况下关闭它。

要说明被删除的行,请看这个提交:

>>> session.commit()
DELETE  FROM  address  WHERE  address.id  =  ?
[...]  (4,)
DELETE  FROM  user_account  WHERE  user_account.id  =  ?
[...]  (3,)
COMMIT 

本教程讨论了 ORM 删除操作,详情请见使用工作单元模式删除 ORM 对象。关于对象过期的背景信息请参考过期/刷新;级联操作在 Cascades 中有详细讨论。

深入学习上述概念

对于新用户来说,上述部分可能是一场令人眼花缭乱的旅程。每个步骤中都有许多重要概念没有涵盖。快速了解事物的外观后,建议通过 SQLAlchemy 统一教程来深入了解上述内容。祝好运!

ORM 映射类配置

原文:docs.sqlalchemy.org/en/20/orm/mapper_config.html

ORM 配置的详细参考,不包括关系,关系详细说明在关系配置。

要快速查看典型的 ORM 配置,请从 ORM 快速入门开始。

要了解 SQLAlchemy 实现的对象关系映射概念,请先查看 SQLAlchemy 统一教程,在使用 ORM 声明形式定义表元数据中介绍。

  • ORM 映射类概述
  • ORM 映射风格
  • 声明性映射
  • 命令式映射
  • 映射类基本组件
  • 待映射的类
  • 表或其他来自子句对象
  • 属性字典
  • 其他映射器配置参数
  • 映射类行为
  • 默认构造函数
  • 跨加载保持非映射状态
  • 映射类、实例和映射器的运行时内省
  • 映射器对象的检查
  • 映射实例的检查
  • 使用声明性映射类
  • 声明性映射风格
  • 使用声明性基类
  • 使用装饰器的声明性映射(无声明性基类)
  • 使用声明性配置表
  • 带有 mapped_column() 的声明性表
  • 使用带注释的声明性表(mapped_column()的类型注释形式)
  • 访问表和元数据
  • 声明性表配置
  • 使用声明性表的显式模式名称
  • 为声明式映射的列设置加载和持久化选项
  • 显式命名声明式映射列
  • 将额外列添加到现有的声明式映射类
  • 使用命令式表进行声明式(即混合声明式)
  • 映射表列的替代属性名
  • 为命令式表列应用加载、持久化和映射选项
  • 使用反射表进行声明式映射
  • 使用延迟反射
  • 使用自动映射
  • 从反射表自动化列命名方案
  • 映射到显式主键列集合
  • 映射表列的子集
  • 声明式映射器配置
  • 使用声明式定义映射属性
  • 声明式的映射器配置选项
  • 动态构建映射器参数
  • 其他声明式映射指令
  • __declare_last__()
  • __declare_first__()
  • metadata
  • __abstract__
  • __table_cls__
  • 使用混合组合映射层次结构
  • 增强基类
  • 混合使用列
  • 混合使用关系
  • _orm.column_property() 和其他 _orm.MapperProperty 类中混合使用
  • 使用混合和基类进行映射继承模式
  • 使用 _orm.declared_attr() 与继承 TableMapper 参数
  • 使用 _orm.declared_attr() 生成表特定的继承列
  • 从多个混合类组合表/映射器参数
  • 使用命名约定在混合类上创建索引和约束
  • 与 dataclasses 和 attrs 集成
  • 声明式数据类映射
  • 类级别功能配置
  • 属性配置
  • 列默认值
  • 与 Annotated 集成
  • 使用混合类和抽象超类
  • 关系配置
  • 使用未映射的数据类字段
  • 与 Pydantic 等替代数据类提供者集成
  • 将 ORM 映射应用于现有的数据类(传统数据类使用)
  • 使用声明式与命令式表映射映射预先存在的数据类
  • 使用声明式样式字段映射预先存在的数据类
  • 使用预先存在的数据类的声明式混合类
  • 使用命令式映射映射预先存在的数据类
  • 将 ORM 映射应用于现有的 attrs 类
  • 使用声明式“命令式表”映射映射属性
  • 使用命令式映射映射属性
  • SQL 表达式作为映射属性
  • 使用混合类
  • 使用 column_property
  • 将 column_property() 添加到现有的声明式映射类
  • 在映射时从列属性组合
  • 使用 column_property() 进行列推迟
  • 使用普通描述符
  • 查询时将 SQL 表达式作为映射属性
  • 更改属性行为
  • 简单验证器
  • validates()
  • 在核心级别使用自定义数据类型
  • 使用描述符和混合物
  • 同义词
  • synonym()
  • 操作符定制
  • 复合列类型
  • 使用映射的复合列类型
  • 复合体的其他映射形式
  • 直接映射列,然后传递给复合体
  • 直接映射列,将属性名称传递给复合体
  • 命令映射和命令表
  • 使用传统非数据类
  • 跟踪复合体上的原位变化
  • 重新定义复合体的比较操作
  • 嵌套复合体
  • 复合体 API
  • composite()
  • 映射类继承层次结构
  • 联接表继承
  • 与联接继承相关的关系
  • 加载联接继承映射
  • 单表继承
  • 使用 use_existing_column 解决列冲突
  • 与单表继承相关的关系
  • 使用 polymorphic_abstract 构建更深层次的层次结构
  • 加载单表继承映射
  • 具体表继承
  • 具体多态加载配置
  • 抽象具体类
  • 经典和半经典具体多态配置
  • 具体继承关系的关系
  • 加载具体继承映射
  • 非传统映射
  • 将类映射到多个表
  • 将类映射到任意子查询
  • 一个类的多个映射器
  • 配置版本计数器
  • 简单版本计数
  • 自定义版本计数器/类型
  • 服务器端版本计数器
  • 编程或条件版本计数器
  • 类映射 API
  • registry
  • registry.__init__()
  • registry.as_declarative_base()
  • registry.configure()
  • registry.dispose()
  • registry.generate_base()
  • registry.map_declaratively()
  • registry.map_imperatively()
  • registry.mapped()
  • registry.mapped_as_dataclass()
  • registry.mappers
  • registry.update_type_annotation_map()
  • add_mapped_attribute()
  • column_property()
  • declarative_base()
  • declarative_mixin()
  • as_declarative()
  • mapped_column()
  • declared_attr
  • declared_attr.cascading
  • declared_attr.directive
  • DeclarativeBase
  • DeclarativeBase.__mapper__
  • DeclarativeBase.__mapper_args__
  • DeclarativeBase.__table__
  • DeclarativeBase.__table_args__
  • DeclarativeBase.__tablename__
  • DeclarativeBase.metadata
  • DeclarativeBase.registry
  • DeclarativeBaseNoMeta
  • DeclarativeBaseNoMeta.__mapper__
  • DeclarativeBaseNoMeta.__mapper_args__
  • DeclarativeBaseNoMeta.__table__
  • DeclarativeBaseNoMeta.__table_args__
  • DeclarativeBaseNoMeta.__tablename__
  • DeclarativeBaseNoMeta.metadata
  • DeclarativeBaseNoMeta.registry
  • has_inherited_table()
  • synonym_for()
  • object_mapper()
  • class_mapper()
  • configure_mappers()
  • clear_mappers()
  • identity_key()
  • polymorphic_union()
  • orm_insert_sentinel()
  • reconstructor()
  • Mapper
  • Mapper.__init__()
  • Mapper.add_properties()
  • Mapper.add_property()
  • Mapper.all_orm_descriptors
  • Mapper.attrs
  • Mapper.base_mapper
  • Mapper.c
  • Mapper.cascade_iterator()
  • Mapper.class_
  • Mapper.class_manager
  • Mapper.column_attrs
  • Mapper.columns
  • Mapper.common_parent()
  • Mapper.composites
  • Mapper.concrete
  • Mapper.configured
  • Mapper.entity
  • Mapper.get_property()
  • Mapper.get_property_by_column()
  • Mapper.identity_key_from_instance()
  • Mapper.identity_key_from_primary_key()
  • Mapper.identity_key_from_row()
  • Mapper.inherits
  • Mapper.is_mapper
  • Mapper.is_sibling()
  • Mapper.isa()
  • Mapper.iterate_properties
  • Mapper.local_table
  • Mapper.mapped_table
  • Mapper.mapper
  • Mapper.non_primary
  • Mapper.persist_selectable
  • Mapper.polymorphic_identity
  • Mapper.polymorphic_iterator()
  • Mapper.polymorphic_map
  • Mapper.polymorphic_on
  • Mapper.primary_key
  • Mapper.primary_key_from_instance()
  • Mapper.primary_mapper()
  • Mapper.relationships
  • Mapper.selectable
  • Mapper.self_and_descendants
  • Mapper.single
  • Mapper.synonyms
  • Mapper.tables
  • Mapper.validators
  • Mapper.with_polymorphic_mappers
  • MappedAsDataclass
  • MappedClassProtocol


SqlAlchemy 2.0 中文文档(四)(3)https://developer.aliyun.com/article/1562996

相关文章
|
4月前
|
测试技术 API 数据库
SqlAlchemy 2.0 中文文档(九)(5)
SqlAlchemy 2.0 中文文档(九)
28 0
|
4月前
|
SQL 数据库 数据库管理
SqlAlchemy 2.0 中文文档(一)(2)
SqlAlchemy 2.0 中文文档(一)
130 1
|
4月前
|
SQL 缓存 关系型数据库
SqlAlchemy 2.0 中文文档(三)(2)
SqlAlchemy 2.0 中文文档(三)
32 1
|
4月前
|
SQL 关系型数据库 测试技术
SqlAlchemy 2.0 中文文档(十)(1)
SqlAlchemy 2.0 中文文档(十)
30 1
|
4月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(三)(1)
SqlAlchemy 2.0 中文文档(三)
40 1
|
4月前
|
SQL JSON 关系型数据库
SqlAlchemy 2.0 中文文档(二)(2)
SqlAlchemy 2.0 中文文档(二)
83 2
|
4月前
|
SQL 自然语言处理 数据库
SqlAlchemy 2.0 中文文档(二)(3)
SqlAlchemy 2.0 中文文档(二)
46 2
|
4月前
|
SQL 测试技术 Python
SqlAlchemy 2.0 中文文档(二)(1)
SqlAlchemy 2.0 中文文档(二)
50 2
|
4月前
|
存储 Python
SqlAlchemy 2.0 中文文档(七)(5)
SqlAlchemy 2.0 中文文档(七)
26 1
|
4月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(五)(1)
SqlAlchemy 2.0 中文文档(五)
44 0