目录

SQLAlchemy 0.7有什么新功能?

优质
小牛编辑
132浏览
2023-12-01

关于此文档

本文档描述了最新发布于2012年5月5日的SQLAlchemy版本0.6和截至2012年10月正在进行维护发布的SQLAlchemy版本0.7之间的更改。

文件日期:2011年7月27日

介绍

本指南介绍了SQLAlchemy 0.7版的新增功能,并记录了影响用户将其应用程序从0.6系列SQLAlchemy迁移到0.7的更改。

在很大程度上,所做的更改不会破坏与为0.6构建的应用程序的兼容性。不一定向后兼容的更改非常少,除了一个之外,对可变属性默认值的更改应该影响非常小的应用程序部分-许多更改涉及非公共API和一些用户可能试图使用的未经记录的黑客。

第二种,甚至更小的非向后兼容的变更也被记录下来。此类更改关注的是那些功能和行为,这些功能和行为至少在0.5版之后已被弃用,并且在弃用之后一直发出警告。这些更改只会影响仍在使用0.4或早期0.5样式API的应用程序。随着项目的成熟,我们在0.x级别的版本中对这些类型的更改越来越少,这是我们的API的一个产品,它具有越来越少的特性,这些特性对于它们要解决的用例来说并不理想。

在sqlacalchemy 0.7中,一系列现有功能已被取代。术语“已取代”和“已弃用”之间没有太大的区别,只是前者对旧特性的建议较弱,将永远不会被删除。在0.7中,功能如下 synonymcomparable_property 以及所有 Extension 和其他事件类,已被取代。但是这些“被取代”的特性已经被重新实现,以至于它们的实现大多不在核心ORM代码中,因此它们持续的“挂起”不会影响SQLAlchemy进一步简化和改进其内部结构的能力,并且我们希望它们在可预见的将来仍留在API中。

新特点

新事件系统

SQLAlchemy从 MapperExtension 类,它提供了映射器的持久性循环的挂钩。随着SQLAlchemy迅速变得更为组件化,将映射器推到一个更为集中的配置角色中,弹出了更多的“扩展”、“侦听器”和“代理”类,以一种特殊的方式解决各种活动拦截用例。部分原因是活动的分歧; ConnectionProxy 对象想要提供一个重写语句和参数的系统; AttributeExtension 提供了一个替换输入值的系统,以及 DDL 对象具有可以关闭方言敏感可调用文件的事件。

0.7使用一种新的统一方法重新实现了几乎所有这些插件点,该方法保留了不同系统的所有功能,提供了更多的灵活性和更少的样板文件,性能更好,并消除了为每个事件子系统学习完全不同的API的需要。现有的类 MapperExtensionSessionExtensionAttributeExtensionConnectionProxyPoolListener 以及 DDLElement.execute_at 方法已被弃用,现在已在新系统中实现-这些API仍然完全正常工作,并且预计在可预见的将来仍将保持原样。

新方法使用命名事件和用户定义的可调用项将活动与事件关联。API的外观和感觉受到jquery、blinker和hibernate等多种来源的驱动,并且在Twitter上与数十名用户举行的会议中,API的外观和感觉也进行了进一步的修改,这似乎比此类问题的邮件列表有更高的响应率。

它还具有一个开放的目标规范系统,允许事件与API类相关联,例如 SessionEngine 对象,具有API类的特定实例,例如 PoolMapper 以及相关对象,如已映射的用户定义类,或映射父类的特定子类实例上的特定属性。单个侦听器子系统可以将包装器应用于传入的用户定义的侦听器函数,这些函数可以修改它们的调用方式-映射器事件可以接收正在操作的对象的实例或其底层 InstanceState 对象。属性事件可以选择是否有返回新值的责任。

一些系统现在建立在新的事件API之上,包括新的“可变属性”API以及复合属性。对事件的更大重视也导致了一些新事件的引入,包括属性过期和刷新操作、pickle加载/转储操作、已完成的映射器构造操作。

参见

事件

#1902

混合属性,实现/取代同义词(),可比较的_属性()

“派生属性”示例现在已转换为正式的扩展。的典型用例 synonym() 提供对映射列的描述符访问;用于 comparable_property() 能够返回 PropComparator 来自任何描述符。实际上,“派生”的方法更容易使用,更具可扩展性,在十几行纯Python中实现,几乎不需要导入,而且不需要ORM核心了解它。这个特性现在被称为“混合属性”扩展。

synonym()comparable_property() 仍然是ORM的一部分,尽管它们的实现已经被向外移动,建立在一种类似于混合扩展的方法之上,这样核心ORM映射器/查询/属性模块就不会真正意识到它们。

参见

混合属性

#1903

速度增强

与所有主要的sqla版本一样,为了减少开销和调用计数,已经进行了广泛的内部传递,这进一步减少了常见场景中所需的工作。此版本的亮点包括:

  • 刷新过程现在将把insert语句捆绑到批处理中 cursor.executemany() ,对于已经存在主键的行。尤其是,这通常适用于联接表继承配置中的“子”表,这意味着对 cursor.execute 对于大量的联合表对象插入,可以将其切成两半,从而允许对传递给 cursor.executemany() (例如重新使用准备好的语句)。

  • 在访问已加载的相关对象的多对一引用时调用的代码路径已经大大简化。直接检查身份图,无需生成新的 Query 对象优先,在数千个内存中,这是很昂贵的,许多对一个被访问。每次调用构建的“加载器”对象的使用也不再用于大多数惰性属性加载。

  • 当映射器内部在一个刷新中访问映射的属性时,复合数据的重写允许一个较短的代码路径。

  • 当“保存更新”和其他层叠操作需要在与属性关联的数据成员的整个范围内层叠时,新的内联属性访问函数将替换先前使用的“历史记录”。这减少了生成新的 History 此速度关键操作的对象。

  • 的内部 ExecutionContext 对应于语句执行的对象已被内联和简化。

  • 这个 bind_processor()result_processor() 现在缓存由类型为每个语句执行生成的可调用文件(小心地,以避免特殊类型和方言的内存泄漏),以延长该类型的使用寿命,从而进一步减少每个语句的调用开销。

  • 特定的“绑定处理器”集合 Compiled 语句的实例也缓存在 Compiled 对象,进一步利用flush进程使用的“已编译缓存”重新使用相同的已编译形式的insert、update、delete语句。

有关呼叫计数减少的演示,包括示例基准脚本,请参见https://techspot.zzzeek.org/2010/12/12/a-tale-of-three-Profiles/

复合材料重写

“复合”特性被重写,比如 synonym()comparable_property() 使用基于描述符和事件的轻量级实现,而不是构建到ORM内部。这允许从映射器/工作单元内部消除一些延迟,并简化组合的工作。复合属性现在不再隐藏它所建立的基础列,这些基础列现在仍然是常规属性。复合材料也可以作为 relationship() 以及 Column() 属性。

组合向后不兼容的主要变化是它们不再使用 mutable=True 检测就地突变的系统。请使用 Mutation Tracking 扩展以建立现有组合使用的就地更改事件。

参见

组合列类型

突变跟踪

#2008 #2024

更简洁的query.join形式(target,onclause)

默认发行方法 query.join() 对于具有显式onclause的目标,现在是:

query.join(SomeClass, SomeClass.id==ParentClass.some_id)

在0.6中,这种用法被认为是错误的,因为 join() 接受与多个联接子句对应的多个参数-两个参数形式需要在一个元组中才能在单个参数和两个参数联接目标之间消除歧义。在0.6的中间,我们为这个特定的调用样式添加了检测和错误消息,因为它非常常见。在0.7中,由于我们无论如何都在检测确切的模式,而且由于无理由地必须键入一个元组是非常烦人的,因此非元组方法现在变成了“正常”的方法。与单连接用例相比,“多连接”用例是非常罕见的,而现在的多连接更明显地由多个对 join() .

元组形式将保持向后兼容性。

注意所有其他形式的 query.join() 保持不变:

query.join(MyClass.somerelation)
query.join("somerelation")
query.join(MyTarget)
# ... etc

Querying with Joins

#1923

突变事件扩展,取代“mutable=true”

一个新的扩展, 突变跟踪 ,提供了一种机制,通过该机制,用户定义的数据类型可以将更改事件返回给所属的父级或父级。扩展包括一种标量数据库值的方法,例如由 PickleTypepostgresql.ARRAY 或其他习俗 MutableType 类,以及ORM“复合”的方法,这些配置使用 composite() .

参见

突变跟踪

nulls first/nulls last运算符

这些是作为对 asc()desc() 运算符,调用 nullsfirst()nullslast() .

参见

nullsfirst()

nullslast()

#723

select.distinct(),query.distinct()接受 * postgresql的args distinct on

通过将表达式列表传递给 distinct 的关键字参数 select() , the distinct() 方法 select()Query 现在接受位置参数,这些参数在使用PostgreSQL后端时呈现为不同的。

distinct()

Query.distinct()

#1069

Index() can be placed inline inside of Table, __table_args__

index()构造可以与表定义内联创建,使用字符串作为列名,作为在表外部创建索引的替代方法。即:

Table('mytable', metadata,
        Column('id',Integer, primary_key=True),
        Column('name', String(50), nullable=False),
        Index('idx_name', 'name')
)

这里的主要理由是为了声明性的利益 __table_args__ 尤其是与混音器一起使用时:

class HasNameMixin(object):
    name = Column('name', String(50), nullable=False)
    @declared_attr
    def __table_args__(cls):
        return (Index('name'), {})

class User(HasNameMixin, Base):
    __tablename__ = 'user'
    id = Column('id', Integer, primary_key=True)

Indexes

窗口函数SQL构造

“窗口函数”向语句提供有关生成结果集的信息。这允许对“行数”、“排名”等各种情况使用条件。已知至少PostgreSQL、SQL Server和Oracle(可能还有其他软件)支持它们。

窗口函数的最佳介绍位于PostgreSQL的站点上,该站点自8.4版起就支持窗口函数:

https://www.postgresql.org/docs/9.0/static/tutorial- window.html

SQLAlchemy提供了一个简单的构造,通常通过现有的函数子句调用,使用 over() 方法,接受 order_bypartition_by 关键字参数。下面我们复制pg教程中的第一个示例:

from sqlalchemy.sql import table, column, select, func

empsalary = table('empsalary',
                column('depname'),
                column('empno'),
                column('salary'))

s = select([
        empsalary,
        func.avg(empsalary.c.salary).
              over(partition_by=empsalary.c.depname).
              label('avg')
    ])

print(s)

SQL:

SELECT empsalary.depname, empsalary.empno, empsalary.salary,
avg(empsalary.salary) OVER (PARTITION BY empsalary.depname) AS avg
FROM empsalary

sqlalchemy.sql.expression.over

#1844

连接上的execution_options()接受“isolation_level”参数

这将为单个 Connection 直到那 Connection 关闭,其基础DBAPI资源返回到连接池,在此基础上,隔离级别重置回默认值。默认隔离级别是使用 isolation_level 参数 create_engine() .

事务隔离支持目前仅受PostgreSQL和SQLite后端支持。

execution_options()

#2001

TypeDecorator 使用整数主键列

A TypeDecorator 它扩展了 Integer 不能与主键列一起使用。的“自动递增”特性 Column 现在将认识到基础数据库列仍然是一个整数,以便lastrowid机制继续工作。这个 TypeDecorator 其结果值处理器将应用于新生成的主键,包括DBAPI接收的主键。 cursor.lastrowid 访问器。

#2005 #2006

TypeDecorator 存在于“sqlacalchemy”导入空间中

不再需要从导入此 sqlalchemy.types ,现在镜像到 sqlalchemy .

新方言

增加了方言:

  • 用于细雨数据库的mysqldb驱动程序:

    Drizzle

  • 对pymysql dbapi的支持:

    pymsql Notes

  • psycopg2现在与python 3一起工作

行为变化(向后兼容)

默认情况下生成C扩展

从0.7b4开始。如果检测到cpython 2.xx,则将生成exts。如果生成失败(如在Windows安装上),则会捕获该情况并继续进行非C安装。如果使用python 3或pypy,C exts将不会构建。

query.count()已简化,应始终有效

发生在 Query.count() 已现代化使用 .from_self() . 也就是说, query.count() 现在相当于:

query.from_self(func.count(literal_column('1'))).scalar()

以前,内部逻辑试图重写查询本身的columns子句,在检测到“subquery”条件(例如可能包含聚合的基于列的查询)或具有distinct的查询时,将经历重写columns子句的复杂过程。这种逻辑在复杂的条件下失败了,特别是那些涉及联合表继承的条件下,而且被更全面的 .from_self() 打电话。

发出的SQL query.count() 现在总是这样:

SELECT count(1) AS count_1 FROM (
    SELECT user.id AS user_id, user.name AS user_name from user
) AS anon_1

也就是说,原始查询完全保留在子查询内部,不需要再猜测应该如何应用计数。

#2093

发出count()的非子查询形式

MySQL用户已经报告说,myisam引擎在这个简单的更改中完全崩溃并不令人惊讶。注意,对于一个简单的 count() 对无法处理简单子查询的DBS进行优化, func.count() 应使用:

from sqlalchemy import func
session.query(func.count(MyClass.id)).scalar()

或为了 count(*)

from sqlalchemy import func, literal_column
session.query(func.count(literal_column('*'))).select_from(MyClass).scalar()

限制/偏移子句现在使用绑定参数

limit和offset子句或其后端等效项(即top、row number over等)对所有支持它的后端(除Sybase之外的大多数后端)使用绑定参数作为实际值。这允许更好的查询优化器性能,因为限制/偏移量不同的多个语句的文本字符串现在是相同的。

#805

日志功能增强

Vinay Sajip为我们的日志系统提供了一个补丁,这样就不再需要在引擎和池的日志语句中嵌入“hex字符串”来允许 echo 正确工作的标志。使用过滤日志对象的新系统允许我们维护 echo 对于单个引擎是本地的,不需要在这些引擎上附加标识字符串。

#1926

简化的多态性分配

人口 polymorphic_on 在继承方案中使用列映射属性时,现在在构造对象(即其 __init__ 使用init事件调用方法。然后,该属性的行为与任何其他列映射属性相同。以前,特殊逻辑会在刷新期间触发以填充此列,这会阻止任何用户代码修改其行为。新方法通过三种方式对此进行了改进:1。一旦被构造,多态性的特性就出现在对象上;2。多态标识可以由用户代码更改,而行为与任何其他列映射属性没有任何区别;3。刷新期间映射器的内部结构被简化,不再需要对此列进行特殊检查。

#1895

包含跨越多个路径(即“all()”)的_-eager()链

这个 `contains_eager() 修饰符现在将自身链接更长的路径,而无需发出单个 ````contains_eager() “电话。而不是:

session.query(A).options(contains_eager(A.b), contains_eager(A.b, B.c))

你可以说:

session.query(A).options(contains_eager(A.b, B.c))

#2032

不允许刷新没有父级的孤立项

我们有一个长期存在的行为,在刷新期间检查所谓的“孤立”对象,即与 relationship() 它指定了“删除-孤立”级联,已为插入而新添加到会话中,并且未建立父关系。这项检查是在几年前添加的,以适应一些测试用例,这些测试用例测试孤立行为的一致性。在现代的sqla中,不再需要在python端进行这种检查。“孤立检查”的等效行为是通过使对对象父行的外键引用不为空来完成的,在这种情况下,数据库执行其建立数据一致性的工作,与sqla允许大多数其他操作执行的相同。如果对象的父外键可以为空,则可以插入该行。“孤立”行为在对象与特定父对象持久化时运行,然后与该父对象解除关联,从而导致为其发出一条删除语句。

#1912

当集合成员、标量引用不是刷新的一部分时生成警告

当通过加载的 relationship() 在标记为“脏”的父对象上当前不存在 Session .

这个 save-update 当对象添加到 Session 或者当对象第一次与父对象关联时,这样一个对象及其相关的所有内容通常都存在于同一个对象中。 Session . 然而,如果 save-update 对特定对象禁用层叠 relationship() ,则不会发生此行为,刷新过程也不会尝试对其进行更正,而是与配置的级联行为保持一致。以前,当在刷新过程中检测到这些对象时,它们会被悄悄地跳过。新的行为是发出一个警告,目的是提醒一种情况,这种情况往往是意外行为的根源。

#1973

安装程序不再安装鼻插件

自从我们移动到nose,我们就使用了一个通过安装工具安装的插件,这样 nosetests 脚本将自动运行sqla的插件代码,这对于我们的测试具有完整的环境是必要的。在0.6的中间,我们意识到这里的导入模式意味着nose的“coverage”插件将中断,因为“coverage”要求在导入任何要覆盖的模块之前启动;因此在0.6的中间,我们通过添加单独的 sqlalchemy-nose 打包到构建中以克服这一点。

在0.7中,我们已经不再尝试 nosetests 自动工作,因为sqlAlchemy模块将为所有使用产生大量的鼻配置选项 nosetests 不仅是sqlAlchemy单元测试自己,而且 sqlalchemy-nose 安装是一个更糟糕的想法,在Python环境中生成一个额外的包。这个 sqla_nose.py 0.7中的脚本现在是用鼻运行测试的唯一方法。

#1949

可以映射非“table”派生的构造

不反对任何 Table 像函数一样,可以映射。

from sqlalchemy import select, func
from sqlalchemy.orm import mapper

class Subset(object):
    pass
selectable = select(["x", "y", "z"]).select_from(func.some_db_function()).alias()
mapper(Subset, selectable, primary_key=[selectable.c.x])

#1876

别名()接受 FromClause 元素

这是一个方便助手,在这种情况下, FromClause ,比如 selectTablejoin 传递给 orm.aliased() 构造,它通过 .alias() 从构造而不是构造一个ORM级别的方法 AliasedClass .

#2018

session.connection(),session.execute()接受“bind”

这允许执行/连接操作显式地参与引擎的打开事务。它还允许自定义子类 Session 实现自己的 get_bind() 方法和参数使用这些自定义参数 execute()connection() 方法相同。

Session.connection Session.execute

#1996

自动标记columns子句中的独立绑定参数。

select的“columns子句”中存在的绑定参数现在像其他“anonymous”子句一样被自动标记,这使得它们的“type”在提取行时(如结果行处理器)具有意义。

sqlite-通过os.path.abspath()规范化相对文件路径

这样,更改当前目录的脚本将继续指向与随后建立的sqlite连接相同的位置。

#2036

MS-SQL String/Unicode /`` varchar``/nvarchar/``varbinary``emit“max”表示无长度

在MS-SQL后端,字符串/unicode类型及其对应的varchar/nvarchar和varbinary (#1833 )当没有指定长度时,将“max”作为长度。这使得它与PostgreSQL的varchar类型更兼容,后者在没有指定长度的情况下同样是无边界的。SQL Server在未指定长度时,将这些类型的长度默认为“1”。

行为变化(向后不兼容)

再次注意,除了默认的可变性更改,这些更改中的大多数都是 * 非常小*不会影响大多数用户。

PickleType 默认情况下关闭数组可变性

当映射具有 PickleTypepostgresql.ARRAY 数据类型。这个 mutable 标志现在设置为 False 默认情况下。如果现有的应用程序使用这些类型,并且依赖于就地突变的检测,则必须使用 mutable=True 要恢复0.6行为:

Table('mytable', metadata,
    # ....

    Column('pickled_data', PickleType(mutable=True))
)

这个 mutable=True 旗帜正在逐步淘汰,取而代之的是新的旗帜 Mutation Tracking 分机。此扩展提供了一种机制,通过该机制,用户定义的数据类型可以将更改事件提供回拥有父级的一个或多个父级。

以前的使用方法 mutable=True 不提供更改事件-相反,ORM必须扫描会话中存在的所有可变值,并将其与每次更改的原始值进行比较。 flush() 被调用,这是一个非常耗时的事件。这是从早期的sqlacalchemy,当 flush() 不是自动的,历史跟踪系统也不像现在这样复杂。

使用的现有应用程序 PickleTypepostgresql.ARRAY 或其他 MutableType 子类,并要求就地突变检测,应迁移到新的突变跟踪系统,如 mutable=True 可能会在将来被弃用。

#1980

变异性检测 composite() 需要突变跟踪扩展

所谓的“复合”映射属性,即使用中描述的技术配置的属性 Composite Column Types ,已经重新实现,以便ORM内部不再知道它们(导致临界区中的代码路径更短、效率更高)。虽然复合类型通常被视为不可变值对象,但这从未强制执行。对于使用具有可变性的组合的应用程序, Mutation Tracking 扩展提供了一个基类,它为用户定义的复合类型建立了一种机制,以便将更改事件消息发送回每个对象的拥有父对象或多个父对象。

使用复合类型并依赖于这些对象的就地突变检测的应用程序应该要么迁移到“突变跟踪”扩展,要么更改复合类型的使用,使就地更改不再需要(即,将它们视为不可变的值对象)。

sqlite-sqlite方言现在使用 NullPool 用于基于文件的数据库

这种变化是 99.999%向后兼容 ,除非您正在跨连接池连接使用临时表。

基于文件的sqlite连接速度非常快,并且使用 NullPool 意味着每次呼叫 Engine.connect 创建新的pysqlite连接。

以前, SingletonThreadPool 这意味着在一个线程中到某个引擎的所有连接都将是相同的连接。新方法的目的是更加直观,特别是在使用多个连接时。

SingletonThreadPool:memory: 使用数据库。

请注意,此更改 中断跨会话提交使用的临时表 ,这取决于SQLite处理临时表的方式。如果需要超出一个池连接范围的临时表,请参阅https://www.sqlalchemy.org/docs/dialects/sqlite.html#using-Temporary-Tables-With-SQLite上的说明。

#1921

Session.merge() 检查版本映射器的版本ID

session.merge()将根据数据库的版本ID检查传入状态的版本ID,假设映射使用版本ID,并且传入状态已分配版本ID,如果它们不匹配,则会引发staledataerror。这是正确的行为,因为如果传入状态包含过时的版本ID,则应假定该状态为过时。

如果将数据合并到版本化状态,则可以不定义版本ID属性,并且不会进行版本检查。

这个检查是通过检查Hibernate做了什么来确认的-两个 merge() 版本控制功能最初是从Hibernate中进行调整的。

#2027

查询中的元组标签名称已改进

对于依赖于旧行为的应用程序,此改进可能稍微向后不兼容。

给定两个映射类 FooBar 每个都有一列 spam

qa = session.query(Foo.spam)
qb = session.query(Bar.spam)

qu = qa.union(qb)

为生成的单个列指定的名称 quspam . 以前是这样的 foo_spam 因为 union 会把与名字不一致的东西组合起来 spam 对于非联合查询。

#1942

映射的列属性首先引用最特定的列

当映射的列属性引用多个列时,这是对所涉及行为的更改,特别是在处理与超类属性同名的联接表子类上的属性时。

使用声明性,场景如下:

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)

class Child(Parent):
   __tablename__ = 'child'
    id = Column(Integer, ForeignKey('parent.id'), primary_key=True)

上面,属性 Child.id 指的是 child.id 列以及 parent.id -这是由于属性的名称。如果它在类上的命名不同,例如 Child.child_id ,然后它清楚地映射到 child.idChild.idParent.id .

id 属性用于引用 parent.idchild.id ,它将它们存储在一个有序的列表中。一种表达式,如 Child.id 然后指的是 one 在渲染时。在0.6之前,此列将 parent.id . 在0.7中,这就不那么令人惊讶了 child.id .

这种行为的遗产处理的是ORM的行为和限制,这些行为和限制不再真正适用;所需要的只是颠倒顺序。

这种方法的一个主要优点是现在更容易构造 primaryjoin 引用本地列的表达式:

class Child(Parent):
   __tablename__ = 'child'
    id = Column(Integer, ForeignKey('parent.id'), primary_key=True)
    some_related = relationship("SomeRelated",
                    primaryjoin="Child.id==SomeRelated.child_id")

class SomeRelated(Base):
   __tablename__ = 'some_related'
    id = Column(Integer, primary_key=True)
    child_id = Column(Integer, ForeignKey('child.id'))

0.7之前 Child.id 表达式将引用 Parent.id 而且有必要绘制地图 child.id 不同的属性。

它还意味着像这样的查询会改变其行为:

session.query(Parent).filter(Child.id > 7)

在0.6中,这将导致:

SELECT parent.id AS parent_id
FROM parent
WHERE parent.id > :id_1

在0.7中,你得到:

SELECT parent.id AS parent_id
FROM parent, child
WHERE child.id > :id_1

你要注意的是一个笛卡尔积-这个行为现在等价于任何其他局部属性的行为。 Child . 这个 with_polymorphic() 方法,或显式加入底层的类似策略 Table 对象,用于呈现对所有 Parent 具有条件的对象 Child ,采用与0.5和0.6相同的方式:

print(s.query(Parent).with_polymorphic([Child]).filter(Child.id > 7))

在0.6和0.7上都显示:

SELECT parent.id AS parent_id, child.id AS child_id
FROM parent LEFT OUTER JOIN child ON parent.id = child.id
WHERE child.id > :id_1

此更改的另一个影响是,两个表之间的联接继承负载将从子表的值而不是父表的值填充。一个不寻常的情况是,对“parent”的查询使用 with_polymorphic="*" 对“parent”发出查询,将左外部联接指向“child”。该行位于“parent”中,看到多态标识对应于“child”,但假设“child”中的实际行已经 删除 . 由于这种损坏,行中与“child”对应的所有列都设置为空-这是现在填充的值,而不是父表中的值。

#1892

映射到具有两个或多个相同命名列的联接需要显式声明

这与之前在 #1892 . 当映射到联接时,相同的命名列必须显式链接到映射的属性,即,如中所述 Mapping a Class Against Multiple Tables .

给两张桌子 foobar ,每个都有一个主键列 id ,以下内容现在产生错误:

foobar = foo.join(bar, foo.c.id==bar.c.foo_id)
mapper(FooBar, foobar)

这是因为 mapper() 拒绝猜测哪个列是主要的表示形式 FooBar.id -是吗? foo.c.id 或者是 bar.c.id ?属性必须是显式的:

foobar = foo.join(bar, foo.c.id==bar.c.foo_id)
mapper(FooBar, foobar, properties={
    'id':[foo.c.id, bar.c.id]
})

#1896

映射器要求在映射的可选对象中存在多态列

这是0.6中的警告,现在是0.7中的错误。给定的列 polymorphic_on 必须在映射的可选项中。这可以防止一些偶尔出现的用户错误,例如:

mapper(SomeClass, sometable, polymorphic_on=some_lookup_table.c.id)

在多态性之上,需要在 sometable 列,在本例中可能是 sometable.c.some_lookup_id . 也有一些“多态结合”的场景,有时会出现类似的错误。

这样的配置错误一直是“错误的”,上面的映射无法按指定方式工作-列将被忽略。然而,在极少数情况下,应用程序在不知情的情况下依赖于此行为,这可能是向后不兼容的。

#1875

DDL() 构造现在转义百分号

以前,登录百分比 DDL() 必须对字符串进行转义,即 %% 取决于DBAPI,对于接受 pyformatformat 绑定(即psycopg2、mysql python),这与 text() 自动执行此操作的构造。现在同样的逃逸发生在 DDL() 至于 text() .

#1897

Table.c / MetaData.tables 有点精致,不允许直接突变

另一个领域是,一些用户以一种不按预期实际工作的方式进行修补,但仍然给某些应用程序依赖于此行为的可能性非常小,由 .c 属性对 Table 以及 .tables 属性对 MetaData 是显式不可变的。构造的“可变”版本现在是私有的。将列添加到 .c 涉及使用 append_column() 方法 Table ,确保事物与父对象关联 Table 以适当的方式;类似地, MetaData.tables 与…有合同 Table 存储在这个字典中的对象,以及一些新的簿记 set() 在所有架构名称中,只有使用公共的 Table 以及 Table.tometadata() .

当然有可能 ColumnCollectiondict 通过这些属性咨询的集合可能有一天会在它们所有的变异方法上实现事件,这样在集合的直接变异时就可以进行适当的簿记,但是直到有人有了实现所有这些方法的动机以及几十个新的单元测试,缩小这些集合的变异路径将确保没有应用程序试图依赖当前不受支持的用法。

#1893 #1917

服务器默认值始终为所有插入的主关键字值返回“无”

当服务器默认值出现在整数pk列上时,建立了一致性。sqla不会预先获取这些,也不会返回到cursor.lastrowid(dbapi)中。确保所有后端在result.inserted的主键中始终不返回任何值-某些后端可能以前返回过值。在主键列上使用服务器默认值是非常罕见的。如果使用特殊的函数或SQL表达式生成主键默认值,则应将其设置为Python端的“默认值”,而不是服务器的“默认值”。

对于这种情况的反射,使用服务器缺省值的int pk col的反射将“autoincrement”标志设置为false,除非在pg serial col中检测到序列缺省值。

#2020 #2021

这个 sqlalchemy.exceptions 已删除sys.modules中的别名

几年来我们一直在添加字符串 sqlalchemy.exceptionssys.modules ,以便类似“import sqlacalchemy.exceptions``”的语句可以工作。核心异常模块的名称 exc 很长一段时间以来,建议导入此模块:

from sqlalchemy import exc

这个 exceptions 对于可能已经说过的应用程序,“sqlacalchemy”中仍然存在名称 from sqlalchemy import exceptions 但是他们也应该开始使用 exc 姓名。

查询定时配方更改

虽然不是SQLAlchemy本身的一部分,但值得一提的是 ConnectionProxy 进入新的事件系统意味着它不再适合“计时所有查询”的方法。请调整查询计时器以使用 before_cursor_execute()after_cursor_execute() 事件,在更新的配方USageRecipes/Profiling中演示。

弃用API

类型上的默认构造函数将不接受参数

简单类型如 IntegerDate 等。在核心类型模块中,不接受参数。接受/忽略catchall的默认构造函数 \*args, \**kwargs 从0.7B4/0.7.0开始恢复,但会发出取消预测警告。

如果参数与类似 Integer ,可能是您打算使用特定方言类型,例如 sqlalchemy.dialects.mysql.INTEGER 例如,它接受一个“显示宽度”参数。

编译_mappers()重命名为configure_mappers(),简化了内部配置

这个系统慢慢地从一个小型的、本地实现的映射器变形为一个单独的映射器,而命名不好的系统则变成了一个更像是全局“注册表”级函数、命名不好的系统,因此我们通过将实现移出 Mapper 把它重新命名为 configure_mappers() . 当然,通常不需要应用程序调用 configure_mappers() 当这个过程根据需要发生时,只要通过属性或查询访问需要映射。

#1966

核心侦听器/代理被事件侦听器取代

PoolListenerConnectionProxyDDLElement.execute_at 被取代 event.listen() ,使用 PoolEventsEngineEventsDDLEvents 分别调度目标。

由事件侦听器取代的ORM扩展

MapperExtension, AttributeExtension, SessionExtension are superseded by event.listen(), using the MapperEvents/InstanceEventsAttributeEventsSessionEvents ,分别调度目标。

在select()中为mysql发送字符串到“distinct”应该通过前缀完成。

这个模糊的特性允许mysql后端使用这种模式:

select([mytable], distinct='ALL', prefixes=['HIGH_PRIORITY'])

这个 prefixes 关键字或 prefix_with() 方法应用于非标准或异常前缀:

select([mytable]).prefix_with('HIGH_PRIORITY', 'ALL')

useexisting superseded by extend_existing and keep_existing

这个 useexisting 表上的标志已被一对新的标志取代 keep_existingextend_existing . extend_existing 等于 useexisting -返回现有表,并添加其他构造函数元素。用 keep_existing ,返回现有表,但不添加其他构造函数元素-这些元素仅在新创建表时应用。

向后不兼容的API更改

可调用文件传递给 bindparam() 不进行评估-影响烧杯示例

#1950

注意,这会影响烧杯缓存示例,其中 _params_from_query() 功能需要稍微调整。如果您使用的是烧杯示例中的代码,那么应该应用此更改。

types.type_map现在是private,types._type_map

我们注意到一些用户在 sqlalchemy.types 作为将Python类型与SQL类型关联的快捷方式。我们不能保证这本字典的内容或格式,另外,以一对一的方式关联Python类型的业务也有一些灰色区域,应该由单个应用程序来最好地确定,因此我们强调了这个属性。

#1870

更名为 alias 独立关键字arg alias() 函数到 name

这样,关键字参数 name 与…相匹配 alias() 所有方法 FromClause 对象以及 name 争论 Query.subquery() .

仅使用独立代码 alias() 函数,而不是方法绑定函数,并使用显式关键字名称传递别名 alias 而不是位置上,这里需要修改。

非公开的 Pool 方法加下划线

所有方法 Pool 而不打算用于公共用途的子类已用下划线重命名。他们以前不是这样命名的,这是一个错误。

池方法现在加下划线或删除:

Pool.create_connection() -> Pool._create_connection()

Pool.do_get() -> Pool._do_get()

Pool.do_return_conn() -> Pool._do_return_conn()

Pool.do_return_invalid() ->已删除,未使用

Pool.return_conn() -> Pool._return_conn()

Pool.get() -> Pool._get(), public API is Pool.connect()

SingletonThreadPool.cleanup() -> _cleanup()

SingletonThreadPool.dispose_local() -> removed, use conn.invalidate()

#1982

以前已弃用,现在已删除

query.join()、query.outerjoin()、chengload()、chengload_all()等不再允许属性列表作为参数

将属性或属性名称列表传递给 Query.joineagerload() ,自0.5起,类似的已被弃用:

# old way, deprecated since 0.5
session.query(Houses).join([Houses.rooms, Room.closets])
session.query(Houses).options(eagerload_all([Houses.rooms, Room.closets]))

这些方法都可以接受 * 从0.5系列开始的参数:

# current way, in place since 0.5
session.query(Houses).join(Houses.rooms, Room.closets)
session.query(Houses).options(eagerload_all(Houses.rooms, Room.closets))

ScopedSession.mapper 被移除

此功能提供了一个映射器扩展,它将基于类的功能与特定的 ScopedSession ,尤其是提供新对象实例将自动与该会话关联的行为。该特性被教程和框架过度使用,由于其隐式行为,导致用户非常困惑,在0.5.5中被弃用。复制其功能的技术位于 [wiki:UsageRecipes/SessionAwareMapper]