SqlAlchemy 2.0 中文文档(五十六)(6)https://developer.aliyun.com/article/1563159
2.0 迁移 - 核心用法
select() 不再接受不同的构造参数,列现在按位置传递
概要
select()
构造以及相关方法 FromClause.select()
将不再接受关键字参数来构建诸如 WHERE 子句、FROM 列表和 ORDER BY 等元素。现在列的列表可以按位置发送,而不是作为列表。此外,case()
构造现在接受其 WHEN 条件按位置传递,而不是作为列表:
# select_from / order_by keywords no longer supported stmt = select([1], select_from=table, order_by=table.c.id) # whereclause parameter no longer supported stmt = select([table.c.x], table.c.id == 5) # whereclause parameter no longer supported stmt = table.select(table.c.id == 5) # list emits a deprecation warning stmt = select([table.c.x, table.c.y]) # list emits a deprecation warning case_clause = case( [(table.c.x == 5, "five"), (table.c.x == 7, "seven")], else_="neither five nor seven", )
迁移到 2.0
只支持“生成”风格的 select()
。应该按位置传递要从中选择的列 / 表的列表。SQLAlchemy 1.4 中的 select()
构造接受传统风格和新风格,使用自动检测方案,因此下面的代码与 1.4 和 2.0 兼容:
# use generative methods stmt = select(1).select_from(table).order_by(table.c.id) # use generative methods stmt = select(table).where(table.c.id == 5) # use generative methods stmt = table.select().where(table.c.id == 5) # pass columns clause expressions positionally stmt = select(table.c.x, table.c.y) # case conditions passed positionally case_clause = case( (table.c.x == 5, "five"), (table.c.x == 7, "seven"), else_="neither five nor seven" )
讨论
多年来,SQLAlchemy 已经发展了一个约定,即 SQL 构造可以接受列表或位置参数作为参数。该约定规定,形成 SQL 语句结构的“结构”元素应该按位置传递。相反,形成 SQL 语句参数化数据的“数据”元素应该作为列表传递。多年来,select()
构造无法顺利参与这个约定,因为“WHERE”子句的传递方式是按位置传递的。SQLAlchemy 2.0 最终通过将 select()
构造更改为仅接受多年来一直是核心教程中唯一记录的样式的“生成”样式来解决了这个问题。
“结构”与“数据”元素的示例如下:
# table columns for CREATE TABLE - structural table = Table("table", metadata_obj, Column("x", Integer), Column("y", Integer)) # columns in a SELECT statement - structural stmt = select(table.c.x, table.c.y) # literal elements in an IN clause - data stmt = stmt.where(table.c.y.in_([1, 2, 3]))
另请参阅
select(),case() 现在接受位置表达式
在“传统”模式下创建的 select() 构造;关键字参数等
插入/更新/删除 DML 不再接受关键字构造参数
概要
与前面对 select()
的更改类似,除了表参数之外,insert()
、update()
和 delete()
的构造参数基本上被移除了:
# no longer supported stmt = insert(table, values={"x": 10, "y": 15}, inline=True) # no longer supported stmt = insert(table, values={"x": 10, "y": 15}, returning=[table.c.x]) # no longer supported stmt = table.delete(table.c.x > 15) # no longer supported stmt = table.update(table.c.x < 15, preserve_parameter_order=True).values( [(table.c.y, 20), (table.c.x, table.c.y + 10)] )
迁移到 2.0
以下示例说明了上述示例的生成方法的使用:
# use generative methods, **kwargs OK for values() stmt = insert(table).values(x=10, y=15).inline() # use generative methods, dictionary also still OK for values() stmt = insert(table).values({"x": 10, "y": 15}).returning(table.c.x) # use generative methods stmt = table.delete().where(table.c.x > 15) # use generative methods, ordered_values() replaces preserve_parameter_order stmt = ( table.update() .where( table.c.x < 15, ) .ordered_values((table.c.y, 20), (table.c.x, table.c.y + 10)) )
讨论
API 和内部正在简化 DML 构造,方式与 select()
构造相似。
select() 不再接受各种构造参数,列按位置传递
概要
select()
构造以及相关方法 FromClause.select()
将不再接受关键字参数来构建 WHERE 子句、FROM 列表和 ORDER BY 等元素。现在列的列表可以按位置发送,而不是作为列表。此外,case()
构造现在接受其 WHEN 条件的位置传递,而不是作为列表:
# select_from / order_by keywords no longer supported stmt = select([1], select_from=table, order_by=table.c.id) # whereclause parameter no longer supported stmt = select([table.c.x], table.c.id == 5) # whereclause parameter no longer supported stmt = table.select(table.c.id == 5) # list emits a deprecation warning stmt = select([table.c.x, table.c.y]) # list emits a deprecation warning case_clause = case( [(table.c.x == 5, "five"), (table.c.x == 7, "seven")], else_="neither five nor seven", )
迁移到 2.0
只支持 select()
的 “生成” 样式。应该将要从中选择的列 / 表的列表位置传递。SQLAlchemy 1.4 中的 select()
构造接受遗留样式和使用自动检测方案的新样式,因此下面的代码与 1.4 和 2.0 兼容:
# use generative methods stmt = select(1).select_from(table).order_by(table.c.id) # use generative methods stmt = select(table).where(table.c.id == 5) # use generative methods stmt = table.select().where(table.c.id == 5) # pass columns clause expressions positionally stmt = select(table.c.x, table.c.y) # case conditions passed positionally case_clause = case( (table.c.x == 5, "five"), (table.c.x == 7, "seven"), else_="neither five nor seven" )
讨论
SQLAlchemy 多年来一直开发了一种约定,用于接受参数作为列表或位置参数的 SQL 构造。这个约定规定,结构元素,即形成 SQL 语句结构的元素,应该以位置方式传递。相反,数据元素,即形成 SQL 语句参数化数据的元素,应该作为列表传递。多年来,select()
构造由于非常古老的调用模式而无法顺利参与这个约定,其中 “WHERE” 子句将以位置方式传递。SQLAlchemy 2.0 最终通过将 select()
构造更改为只接受多年来一直是核心教程中唯一记录的样式的 “生成” 样式来解决了这个问题。
“结构”与“数据”元素的示例如下:
# table columns for CREATE TABLE - structural table = Table("table", metadata_obj, Column("x", Integer), Column("y", Integer)) # columns in a SELECT statement - structural stmt = select(table.c.x, table.c.y) # literal elements in an IN clause - data stmt = stmt.where(table.c.y.in_([1, 2, 3]))
另请参阅
select(), case() 现在接受位置表达式
select()
构造创建为“遗留”模式;关键字参数等
insert/update/delete DML 不再接受关键字构造函数参数
概要
与之前对 select()
的更改类似,除表参数之外的 insert()
、update()
和 delete()
的构造函数参数基本上被移除:
# no longer supported stmt = insert(table, values={"x": 10, "y": 15}, inline=True) # no longer supported stmt = insert(table, values={"x": 10, "y": 15}, returning=[table.c.x]) # no longer supported stmt = table.delete(table.c.x > 15) # no longer supported stmt = table.update(table.c.x < 15, preserve_parameter_order=True).values( [(table.c.y, 20), (table.c.x, table.c.y + 10)] )
迁移到 2.0
以下示例说明了用于上述示例的生成方法的使用:
# use generative methods, **kwargs OK for values() stmt = insert(table).values(x=10, y=15).inline() # use generative methods, dictionary also still OK for values() stmt = insert(table).values({"x": 10, "y": 15}).returning(table.c.x) # use generative methods stmt = table.delete().where(table.c.x > 15) # use generative methods, ordered_values() replaces preserve_parameter_order stmt = ( table.update() .where( table.c.x < 15, ) .ordered_values((table.c.y, 20), (table.c.x, table.c.y + 10)) )
讨论
与 select()
构造一样,DML 构造的 API 和内部正在以类似的方式简化。
2.0 迁移 - ORM 配置
声明式成为一流的 API
概要
sqlalchemy.ext.declarative
包大部分(有一些例外)已移至sqlalchemy.orm
包。declarative_base()
和declared_attr()
函数存在,没有任何行为变化。一个名为registry
的新超级实现现在作为顶级 ORM 配置构造,还提供基于装饰器的声明性和与声明性注册表集成的经典映射的新支持。
迁移到 2.0 版本
更改导入:
from sqlalchemy.ext import declarative_base, declared_attr
至:
from sqlalchemy.orm import declarative_base, declared_attr
讨论
大约十年后,sqlalchemy.ext.declarative
包现在已集成到sqlalchemy.orm
命名空间中,除了保留为声明性扩展的“extension”类。更多详细信息请参阅 1.4 迁移指南中的声明性现在与新功能集成到 ORM 中。
另请参阅
ORM 映射类概述 - 用于声明性、经典映射、数据类、attrs 等的全新统一文档。
声明性现在与新功能集成到 ORM 中
原始的“mapper()”函数现在是声明性的核心元素,已重命名
概要
sqlalchemy.orm.mapper()
独立函数在幕后移动,由更高级别的 API 调用。这个函数的新版本是从registry
对象中获取的方法registry.map_imperatively()
。
迁移到 2.0 版本
与经典映射一起工作的代码应更改导入和代码从:
from sqlalchemy.orm import mapper mapper(SomeClass, some_table, properties={"related": relationship(SomeRelatedClass)})
从中心registry
对象开始工作:
from sqlalchemy.orm import registry mapper_reg = registry() mapper_reg.map_imperatively( SomeClass, some_table, properties={"related": relationship(SomeRelatedClass)} )
上述registry
也是声明性映射的来源,经典映射现在可以访问此注册表,包括基于字符串的配置在relationship()
上:
from sqlalchemy.orm import registry mapper_reg = registry() Base = mapper_reg.generate_base() class SomeRelatedClass(Base): __tablename__ = "related" # ... mapper_reg.map_imperatively( SomeClass, some_table, properties={ "related": relationship( "SomeRelatedClass", primaryjoin="SomeRelatedClass.related_id == SomeClass.id", ) }, )
讨论
应要求,“经典映射”仍然存在,但其新形式基于registry
对象,并且可通过registry.map_imperatively()
使用。
此外,“经典映射”的主要理由是将 Table
设置与类分开。声明性始终允许使用所谓的 混合声明性 风格。但是,为了消除基类要求,已添加了一流的 装饰器 形式。
作为另一个单独但相关的增强,还支持 Python 数据类,并添加到声明性装饰器和经典映射形式中。
另见
ORM 映射类概述 - 所有新的统一文档,涵盖声明性、经典映射、数据类、attrs 等。
声明性成为一流 API
概述
sqlalchemy.ext.declarative
包大部分,除了一些例外,都已移至 sqlalchemy.orm
包中。declarative_base()
和 declared_attr()
函数存在,没有任何行为变化。一个名为 registry
的新超级实现现在作为顶级 ORM 配置构造存在,它还提供了基于装饰器的声明性和与声明性注册表集成的经典映射的新支持。
迁移到 2.0
更改导入:
from sqlalchemy.ext import declarative_base, declared_attr
为:
from sqlalchemy.orm import declarative_base, declared_attr
讨论
十多年来备受欢迎的 sqlalchemy.ext.declarative
包现已整合到 sqlalchemy.orm
命名空间中,但声明性“扩展”类除外,它们仍然作为声明性扩展。更多详细信息请参阅 1.4 迁移指南的 声明性现在已经与带有新特性的 ORM 整合。
另见
ORM 映射类概述 - 所有新的统一文档,涵盖声明性、经典映射、数据类、attrs 等。
声明性现在已经与带有新特性的 ORM 整合
最初的 “mapper()” 函数现在成为声明性的核心元素,重命名为
概述
sqlalchemy.orm.mapper()
独立函数在幕后移动,由更高级别的 API 调用。此函数的新版本是从 registry
对象中获取的方法 registry.map_imperatively()
。
迁移到 2.0
与经典映射一起工作的代码应该从以下形式的导入和代码更改为:
from sqlalchemy.orm import mapper mapper(SomeClass, some_table, properties={"related": relationship(SomeRelatedClass)})
从一个中心registry
对象中工作:
from sqlalchemy.orm import registry mapper_reg = registry() mapper_reg.map_imperatively( SomeClass, some_table, properties={"related": relationship(SomeRelatedClass)} )
上述registry
也是声明式映射的来源,经典映射现在也可以访问此注册表,包括基于字符串的配置在relationship()
上:
from sqlalchemy.orm import registry mapper_reg = registry() Base = mapper_reg.generate_base() class SomeRelatedClass(Base): __tablename__ = "related" # ... mapper_reg.map_imperatively( SomeClass, some_table, properties={ "related": relationship( "SomeRelatedClass", primaryjoin="SomeRelatedClass.related_id == SomeClass.id", ) }, )
讨论
受欢迎的需求,“经典映射”仍然存在,但是它的新形式是基于registry
对象,并且可作为registry.map_imperatively()
使用。
此外,“经典映射”所使用的主要原理是将Table
的设置与类别区分开来。声明式一直以来都允许使用所谓的混合声明式来采用这种风格。然而,为了去除基类的要求,首先增加了一种一流的装饰器形式。
作为另一个单独但相关的增强,还添加了对 Python 数据类的支持,可以同时用于声明式装饰器和经典映射形式。
另请参阅
ORM Mapped Class Overview - 为声明式、经典映射、数据类、attrs 等提供的全新统一文档。
SqlAlchemy 2.0 中文文档(五十六)(8)https://developer.aliyun.com/article/1563161