SQLAlchemy 2.0 文档
变更和迁移
- SQLAlchemy 2.0 - 主要迁移指南
- SQLAlchemy 2.0 的新功能?
- 2.0 更新日志
- 1.4 更新日志
- 1.3 更新日志
- 1.2 更新日志
- 1.1 更新日志
- 1.0 更新日志
- 0.9 更新日志
- 0.8 更新日志
- 0.7 更新日志
- 0.6 更新日志
- 0.5 更新日志
- 0.4 更新日志
- 0.3 更新日志
- 0.2 更新日志
- 0.1 更新日志
- SQLAlchemy 1.4 的新功能?
- SQLAlchemy 1.3 的新功能?
- SQLAlchemy 1.2 的新功能?
- SQLAlchemy 1.1 的新功能?
- SQLAlchemy 1.0 的新功能?
- SQLAlchemy 0.9 的新功能?
- SQLAlchemy 0.8 的新功能?
- SQLAlchemy 0.7 的新功能?
- SQLAlchemy 0.6 的新功能?
- SQLAlchemy 0.5 的新功能?¶
- SQLAlchemy 0.4 的新功能?
项目版本
SQLAlchemy 0.5 的新功能?¶
关于本文档
本文档描述了 SQLAlchemy 版本 0.4(上次发布于 2008 年 10 月 12 日)和 SQLAlchemy 版本 0.5(上次发布于 2010 年 1 月 16 日)之间的变更。
文档日期:2009 年 8 月 4 日
本指南记录了 API 变更,这些变更会影响用户将其应用程序从 SQLAlchemy 的 0.4 系列迁移到 0.5。也建议那些使用 Essential SQLAlchemy 的用户阅读,该书仅涵盖 0.4,甚至似乎还有一些旧的 0.3 的痕迹。请注意,SQLAlchemy 0.5 移除了在 0.4 系列的整个跨度中已弃用的许多行为,并且还弃用了更多特定于 0.4 的行为。
主要文档变更¶
文档的某些部分已完全重写,可以作为新 ORM 特性的介绍。Query 和 Session 对象尤其在 API 和行为上存在一些明显的差异,这些差异从根本上改变了许多基本操作的完成方式,尤其是在构建高度定制的 ORM 查询以及处理过时的会话状态、提交和回滚方面。
弃用源¶
另一个信息来源记录在一系列单元测试中,这些测试说明了一些常见的 Query 模式的最新用法;可以在 [source:sqlalchemy/trunk/test/orm/test_deprecations.py] 查看此文件。
需求变更¶
需要 Python 2.4 或更高版本。SQLAlchemy 0.4 系列是最后一个支持 Python 2.3 的版本。
对象关系映射¶
Query 中的列级别表达式。 - 如 教程 中详述,
Query具有创建特定 SELECT 语句的能力,而不仅仅是针对完整行的语句session.query(User.name, func.count(Address.id).label("numaddresses")).join( Address ).group_by(User.name)
任何多列/实体查询返回的元组都是命名’ 元组
for row in ( session.query(User.name, func.count(Address.id).label("numaddresses")) .join(Address) .group_by(User.name) ): print("name", row.name, "number", row.numaddresses)
Query具有statement访问器,以及subquery()方法,这些方法允许使用Query创建更复杂的组合subq = ( session.query(Keyword.id.label("keyword_id")) .filter(Keyword.name.in_(["beans", "carrots"])) .subquery() ) recipes = session.query(Recipe).filter( exists() .where(Recipe.id == recipe_keywords.c.recipe_id) .where(recipe_keywords.c.keyword_id == subq.c.keyword_id) )
建议对别名连接使用显式 ORM 别名 -
aliased()函数生成类的“别名”,允许在 ORM 查询中精细控制别名。虽然表级别别名(即table.alias())仍然可用,但 ORM 级别别名保留了 ORM 映射对象的语义,这对于继承映射、选项和其他场景非常重要。例如:Friend = aliased(Person) session.query(Person, Friend).join((Friend, Person.friends)).all()
query.join() 大大增强。 - 现在可以以多种方式指定连接的目标和 ON 子句。可以单独提供目标类,其中 SQLA 将尝试通过外键形成与它的连接,方式与
table.join(someothertable)相同。可以提供目标和显式的 ON 条件,其中 ON 条件可以是relation()名称、实际的类描述符或 SQL 表达式。或者,仅使用relation()名称或类描述符的旧方法也有效。请参阅 ORM 教程,其中有几个示例。建议对不需要(并且不偏好)表和映射器之间抽象的应用程序使用声明式 - [/docs/05/reference/ext/declarative.html 声明式] 模块用于组合
Table、mapper()和用户定义的类对象的表达式,强烈建议使用,因为它简化了应用程序配置,确保了“每个类一个映射器”的模式,并允许 distinctmapper()调用可用的全部配置范围。单独的mapper()和Table用法现在被称为“经典 SQLAlchemy 用法”,当然可以与声明式自由混合使用。已从类中移除 .c. 属性(即
MyClass.c.somecolumn)。与 0.4 中的情况一样,类级别属性可用作查询元素,即Class.c.propname现在被Class.propname取代,并且c属性继续保留在Table对象上,在其中它们指示表上存在的Column对象的命名空间。要获取映射类的 Table(如果您没有事先保留它)
table = class_mapper(someclass).mapped_table
迭代列
for col in table.c: print(col)
处理特定列
table.c.somecolumn
类绑定的描述符支持全套 Column 运算符以及记录在案的面向关系的运算符,如
has()、any()、contains()等。硬性移除
.c.的原因是,在 0.5 中,类绑定的描述符可能带有不同的含义,以及关于类映射的信息,而不是普通的Column对象 - 并且在某些用例中,您可能特别希望使用其中一个或另一个。通常,使用类绑定的描述符会调用一组映射/多态感知转换,而使用表绑定的列则不会。在 0.4 中,这些转换应用于所有表达式,但 0.5 完全区分列和映射的描述符,仅对后者应用转换。因此,在许多情况下,尤其是在处理连接表继承配置以及使用query(<columns>)时,Class.propname和table.c.colname不是可互换的。例如,
session.query(users.c.id, users.c.name)与session.query(User.id, User.name)不同;在后一种情况下,Query知道正在使用的映射器,并且可以使用进一步特定于映射器的操作,如query.join(<propname>)、query.with_parent()等,但在前一种情况下则不能。此外,在多态继承场景中,类绑定的描述符引用多态可选对象中存在的列,而不一定是直接对应于描述符的表列。例如,一组通过连接表继承与person表沿每个表的person_id列相关的类都将它们的Class.person_id属性映射到person中的person_id列,而不是它们的子类表。版本 0.4 会自动将此行为映射到表绑定的Column对象。在 0.5 中,此自动转换已被移除,因此您实际上可以使用表绑定的列作为覆盖多态查询中发生的转换的一种手段;这允许Query能够在使用连接表或具体表继承设置以及可移植子查询等之间创建优化的选择。会话现在默认自动与事务同步。 会话现在默认情况下自动与事务同步,包括自动刷新和自动过期。除非使用
autocommit选项禁用事务,否则事务始终存在。当所有三个标志都设置为默认值时,会话在回滚后可以优雅地恢复,并且很难将过时的数据放入会话中。有关详细信息,请参阅新的会话文档。隐式 Order By 已移除。这将影响依赖 SA 的“隐式排序”行为的 ORM 用户,该行为声明所有没有
order_by()的 Query 对象都将 ORDER BY 主映射表的“id”或“oid”列,并且所有延迟/急切加载的集合都应用类似的排序。在 0.5 中,必须在mapper()和relation()对象上显式配置自动排序(如果需要),或者在使用Query时显式配置。要将 0.4 映射转换为 0.5,使其排序行为与 0.4 或以前的版本非常相似,请在
mapper()和relation()上使用order_by设置mapper( User, users, properties={"addresses": relation(Address, order_by=addresses.c.id)}, order_by=users.c.id, )
要在反向引用上设置排序,请使用
backref()函数"keywords": relation( Keyword, secondary=item_keywords, order_by=keywords.c.name, backref=backref("items", order_by=items.c.id), )
使用声明式?为了帮助新的
order_by要求,order_by和 friends 现在可以使用字符串设置,这些字符串稍后在 Python 中计算(这仅适用于声明式,不适用于普通映射器)class MyClass(MyDeclarativeBase): ... "addresses": relation("Address", order_by="Address.id")
通常最好在加载基于列表的项集合的
relation()s上设置order_by,因为否则无法影响该排序。除此之外,最佳实践是使用Query.order_by()来控制正在加载的主实体的排序。会话现在是 autoflush=True/autoexpire=True/autocommit=False。 - 要进行设置,只需调用不带参数的
sessionmaker()。名称transactional=True现在是autocommit=False。刷新发生在每个发出的查询时(使用autoflush=False禁用),在每个commit()中(始终如此),以及在每个begin_nested()之前(因此回滚到 SAVEPOINT 是有意义的)。所有对象在每次commit()和每次rollback()后都会过期。回滚后,挂起的对象将被清除,已删除的对象将移回持久状态。这些默认值协同工作得非常好,并且真的不再需要旧技术,如clear()(已重命名为expunge_all())。附言:会话在
rollback()后现在是可重用的。标量和集合属性更改、添加和删除都会回滚。session.add() 替换 session.save()、session.update()、session.save_or_update()。 -
session.add(someitem)和session.add_all([list of items])方法替换save()、update()和save_or_update()。这些方法将在整个 0.5 版本中保持弃用状态。反向引用配置变得不那么冗长。 -
backref()函数现在使用前向relation()的primaryjoin和secondaryjoin参数,当它们未显式声明时。不再需要在两个方向上分别指定primaryjoin/secondaryjoin。简化的多态选项。 - ORM 的“多态加载”行为已得到简化。在 0.4 中,mapper() 有一个名为
polymorphic_fetch的参数,可以配置为select或deferred。此选项已移除;映射器现在只会延迟 SELECT 语句中不存在的任何列。使用的实际 SELECT 语句由with_polymorphic映射器参数(也在 0.4 中,并替换select_table)以及Query上的with_polymorphic()方法(也在 0.4 中)控制。继承类的延迟加载的一个改进是,映射器现在在所有情况下都生成 SELECT 语句的“优化”版本;也就是说,如果类 B 继承自 A,并且只有类 B 上存在的几个属性已过期,则刷新操作将仅在 SELECT 语句中包含 B 的表,而不会 JOIN 到 A。
Session上的execute()方法将普通字符串转换为text()构造,因此所有绑定参数都可以指定为“:bindname”,而无需显式调用text()。如果此处需要“原始”SQL,请使用session.connection().execute("raw text")。session.Query().iterate_instances()已重命名为仅instances()。返回列表而不是迭代器的旧instances()方法不再存在。如果您依赖该行为,则应使用list(your_query.instances())。
扩展 ORM¶
在 0.5 中,我们正在推进更多修改和扩展 ORM 的方法。以下是摘要
MapperExtension。 - 这是经典的扩展类,仍然存在。很少需要的方法是
create_instance()和populate_instance()。要控制从数据库加载对象时的初始化,请使用reconstruct_instance()方法,或更轻松地使用文档中描述的@reconstructor装饰器。SessionExtension。 - 这是一个易于使用的会话事件扩展类。特别是,它提供了
before_flush()、after_flush()和after_flush_postexec()方法。在许多情况下,建议使用此用法而不是MapperExtension.before_XXX,因为在before_flush()中,您可以自由修改会话的刷新计划,这是无法从MapperExtension中完成的。AttributeExtension。 - 此类现在是公共 API 的一部分,允许拦截属性上的用户级事件,包括属性设置和删除操作,以及集合追加和移除。它还允许修改要设置或追加的值。文档中描述的
@validates装饰器提供了一种快速方法,可以将任何映射的属性标记为由特定的类方法“验证”。属性检测自定义。 - 为雄心勃勃地完全替换 SQLAlchemy 的属性检测或仅在某些情况下对其进行增强提供了 API。此 API 是为 Trellis 工具包的目的而生成的,但作为公共 API 提供。在
/examples/custom_attributes目录中的发行版中提供了一些示例。
模式/类型¶
没有长度的 String 不再生成 TEXT,而是生成 VARCHAR - 当指定不带长度时,
String类型不再神奇地转换为Text类型。这仅在发出 CREATE TABLE 时才有效,因为它将发出不带长度参数的VARCHAR,这在许多(但不是全部)数据库上无效。要创建 TEXT(或 CLOB,即无界字符串)列,请使用Text类型。mutable=True 的 PickleType() 需要 __eq__() 方法 - 当 mutable=True 时,
PickleType类型需要比较值。比较pickle.dumps()的方法效率低下且不可靠。如果传入的对象未实现__eq__()并且也不是None,则使用dumps()比较,但会引发警告。对于实现__eq__()的类型,包括所有字典、列表等,比较将使用==,并且现在默认情况下是可靠的。已移除 TypeEngine/TypeDecorator 的 convert_bind_param() 和 convert_result_value() 方法。 - O’Reilly 书籍不幸地记录了这些方法,即使它们在 0.3 后已弃用。对于用户定义的子类化
TypeEngine的类型,bind_processor()和result_processor()方法应用于绑定/结果处理。任何用户定义的类型,无论是扩展TypeEngine还是TypeDecorator,如果使用旧的 0.3 样式,都可以使用以下适配器轻松适应新样式class AdaptOldConvertMethods(object): """A mixin which adapts 0.3-style convert_bind_param and convert_result_value methods """ def bind_processor(self, dialect): def convert(value): return self.convert_bind_param(value, dialect) return convert def result_processor(self, dialect): def convert(value): return self.convert_result_value(value, dialect) return convert def convert_result_value(self, value, dialect): return value def convert_bind_param(self, value, dialect): return value
要使用上面的 mixin
class MyType(AdaptOldConvertMethods, TypeEngine): ...
Column和Table上的quote标志以及Table上的quote_schema标志现在同时控制正向和负向的引用。默认值为None,表示让常规引用规则生效。当True时,强制启用引用。当False时,强制禁用引用。现在可以使用
Column(..., server_default='val')更方便地指定列DEFAULT值 DDL,弃用Column(..., PassiveDefault('val'))。default=现在专门用于 Python 启动的默认值,并且可以与 server_default 共存。新的server_default=FetchedValue()替换了PassiveDefault('')习惯用法,用于将列标记为受外部触发器影响,并且没有 DDL 副作用。SQLite 的
DateTime、Time和Date类型现在仅接受 datetime 对象,而不是字符串作为绑定参数输入。如果您想创建自己的“混合”类型,该类型接受字符串并将结果作为日期对象返回(从您想要的任何格式),请创建一个基于String构建的TypeDecorator。如果您只想使用基于字符串的日期,请仅使用String。此外,
DateTime和Time类型,当与 SQLite 一起使用时,现在以与str(datetime)相同的方式表示 Pythondatetime.datetime对象的“微秒”字段 - 作为秒的小数部分,而不是微秒计数。那是dt = datetime.datetime(2008, 6, 27, 12, 0, 0, 125) # 125 usec # old way "2008-06-27 12:00:00.125" # new way "2008-06-27 12:00:00.000125"
因此,如果现有的基于 SQLite 文件的数据库打算在 0.4 和 0.5 之间使用,则您必须升级 datetime 列以存储新格式(注意:请测试这一点,我很确定它是正确的)
UPDATE mytable SET somedatecol = substr(somedatecol, 0, 19) || '.' || substr((substr(somedatecol, 21, -1) / 1000000), 3, -1);
或者,按如下方式启用“旧”模式
from sqlalchemy.databases.sqlite import DateTimeMixin DateTimeMixin.__legacy_microseconds__ = True
连接池默认不再是线程本地¶
0.4 有一个不幸的默认设置“pool_threadlocal=True”,例如,当在单个线程中使用多个会话时,会导致意外行为。此标志在 0.5 中现在已关闭。要重新启用 0.4 的行为,请将 pool_threadlocal=True 指定给 create_engine(),或者使用通过 strategy="threadlocal" 的“threadlocal”策略。
接受 *args,不再接受 *args¶
method(\*args) 与 method([args]) 的策略是,如果方法接受表示固定结构的可变长度的项集,则它采用 \*args。如果方法接受数据驱动的可变长度的项集,则它采用 [args]。
各种 Query.options() 函数
eagerload()、eagerload_all()、lazyload()、contains_eager()、defer()、undefer()现在都接受可变长度的\*keys作为它们的参数,这允许使用描述符制定路径,即:query.options(eagerload_all(User.orders, Order.items, Item.keywords))
为了向后兼容,仍然接受单个数组参数。
同样,
Query.join()和Query.outerjoin()方法接受可变长度的 *args,为了向后兼容,也接受单个数组query.join("orders", "items") query.join(User.orders, Order.items)
列上的
in_()方法和类似方法现在只接受列表参数。它不再接受\*args。
已移除¶
entity_name - 此功能一直存在问题且很少使用。0.5 更深入地充实了用例,揭示了
entity_name的进一步问题,导致其被移除。如果单个类需要不同的映射,请将该类分解为单独的子类并分别映射它们。有关示例,请参见 [wiki:UsageRecipes/EntityName]。有关基本原理的更多信息,请参见 https://groups.google.c om/group/sqlalchemy/browse_thread/thread/9e23a0641a88b96d? hl=en 。get()/load() 清理
已移除
load()方法。它的功能有点武断,基本上是从 Hibernate 复制过来的,在 Hibernate 中它也不是一个特别有意义的方法。要获得等效功能
x = session.query(SomeClass).populate_existing().get(7)
已移除
Session.get(cls, id)和Session.load(cls, id)。Session.get()与session.query(cls).get(id)相比是冗余的。也已移除
MapperExtension.get()(MapperExtension.load()也是如此)。要覆盖Query.get()的功能,请使用子类class MyQuery(Query): def get(self, ident): ... session = sessionmaker(query_cls=MyQuery)() ad1 = session.query(Address).get(1)
sqlalchemy.orm.relation()已移除以下已弃用的关键字参数
foreignkey、association、private、attributeext、is_backref
特别是,
attributeext被extension替换 -AttributeExtension类现在位于公共 API 中。session.Query()已移除以下已弃用的函数
list、scalar、count_by、select_whereclause、get_by、select_by、join_by、selectfirst、selectone、select、execute、select_statement、select_text、join_to、join_via、selectfirst_by、selectone_by、apply_max、apply_min、apply_avg、apply_sum
此外,已移除
join()、outerjoin()、add_entity()和add_column()的id关键字参数。要在Query中将表别名定向到结果列,请使用aliased构造from sqlalchemy.orm import aliased address_alias = aliased(Address) print(session.query(User, address_alias).join((address_alias, User.addresses)).all())
sqlalchemy.orm.Mapperinstances()
get_session() - 此方法不是很引人注目,但即使父对象完全分离,当使用诸如
scoped_session()或旧的SessionContextExt之类的扩展时,它也具有将延迟加载与特定会话关联的效果。某些依赖此行为的应用程序可能不再按预期工作;但此处更好的编程实践是始终确保对象存在于会话中,如果需要从其属性进行数据库访问。
mapper(MyClass, mytable)映射类不再使用“c”类属性进行检测;例如
MyClass.csqlalchemy.orm.collectionsprepare_instrumentation 的别名 _prepare_instrumentation 已被移除。
sqlalchemy.orm移除了
EXT_CONTINUE的别名EXT_PASS。sqlalchemy.engine从
DefaultDialect.preexecute_sequences到.preexecute_pk_sequences的别名已被移除。已移除弃用的 engine_descriptors() 函数。
sqlalchemy.ext.activemapper模块已移除。
sqlalchemy.ext.assignmapper模块已移除。
sqlalchemy.ext.associationproxy代理的
.append(item, \**kw)上关键字参数的传递已被移除,现在只需使用.append(item)sqlalchemy.ext.selectresults,sqlalchemy.mods.selectresults模块已移除。
sqlalchemy.ext.declarative已移除
declared_synonym()。sqlalchemy.ext.sessioncontext模块已移除。
sqlalchemy.log到
sqlalchemy.exc.SADeprecationWarning的别名SADeprecationWarning已被移除。sqlalchemy.exc已移除
exc.AssertionError,其用法已替换为同名的 Python 内置异常。sqlalchemy.databases.mysql已移除弃用的
get_version_info方言方法。
重命名或移动¶
sqlalchemy.exceptions现在是sqlalchemy.exc在 0.6 版本之前,该模块仍然可以使用旧名称导入。
FlushError,ConcurrentModificationError,UnmappedColumnError-> sqlalchemy.orm.exc这些异常已移动到 orm 包。导入 'sqlalchemy.orm' 将在 sqlalchemy.exc 中安装别名以实现兼容性,直到 0.6 版本。
sqlalchemy.logging->sqlalchemy.log此内部模块已重命名。当使用 py2app 和类似的扫描导入的工具打包 SA 时,不再需要特殊处理。
session.Query().iterate_instances()->session.Query().instances()。
已弃用¶
Session.save(),Session.update(),Session.save_or_update()这三个方法都已被
Session.add()替代。sqlalchemy.PassiveDefault使用
Column(server_default=...),底层转换为 sqlalchemy.DefaultClause()。session.Query().iterate_instances()。它已被重命名为instances()。
flambé! 龙和 The Alchemist 图像设计由 Rotem Yaari 创作并慷慨捐赠。
使用 Sphinx 7.2.6 创建。文档最后生成于:Tue 11 Mar 2025 02:40:17 PM EDT