版本:1.1.0b2 |发布日期:2016年7月1日

SQLAlchemy 1.1文档

更改和迁移

项目版本

SQLAlchemy 0.7有什么新东西?

关于本文档

本文档介绍2012年5月5日发布的SQLAlchemy版本0.6和2012年10月发布的SQLAlchemy版本0.7之间的更改。

文件日期:2011年7月27日

引言¶ T0>

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

在尽可能大的程度上,进行更改的方式不会中断与为0.6构建的应用程序的兼容性。这些必须不是向后兼容的更改是非常少的,除了一个之外,对可变属性默认值的更改都会影响应用程序的极小部分 - 许多更改涉及非公共API和某些用户可能已经无证书攻击试图使用。

还记录了第二类甚至更小的非向后兼容更改。这类更改将至少从版本0.5开始已经被弃用的那些特性和行为视为已被弃用的警告。这些更改只会影响仍使用0.4或早期0.5样式API的应用程序。随着项目的成熟,我们在0.x级别版本中所发生的这种变化越来越少,这是我们的API产品的功能越来越少,对于他们所要解决的用例而言,这些功能并不理想。

SQLAlchemy 0.7已经取代了现有的一些功能。“被取代”和“被弃用”这两个术语之间没有什么区别,只是前者有一个比较弱的建议,旧的功能将被删除。在0.7中,像synonymcomparable_property以及所有Extension和其他事件类的功能已被取代。但是这些被“取代”的特性已经被重新实现,使得它们的实现大部分都是在核心ORM代码之外生存,所以它们持续的“徘徊”不会影响SQLAlchemy进一步简化和优化其内部的能力,我们期望它们保持不变在可预见的未来的API内。

新功能

新事件系统

SQLAlchemy很早就开始使用MapperExtension类,它提供了映射器持久化周期的钩子。随着SQLAlchemy迅速变得更加组件化,将映射器推进到一个更有针对性的配置角色中,弹出了更多的“扩展”,“监听器”和“代理”类,以特殊的方式解决各种活动拦截用例。Part of this was driven by the divergence of activities; ConnectionProxy objects wanted to provide a system of rewriting statements and parameters; AttributeExtension provided a system of replacing incoming values, and DDL objects had events that could be switched off of dialect-sensitive callables.

0.7重新实现了几乎所有这些插件点,采用新的统一方法,保留了不同系统的所有功能,提供了更多的灵活性,更少的样板,更好的执行,并且不需要为每个事件子系统学习截然不同的API 。The pre-existing classes MapperExtension, SessionExtension, AttributeExtension, ConnectionProxy, PoolListener as well as the DDLElement.execute_at method are deprecated and now implemented in terms of the new system - these APIs remain fully functional and are expected to remain in place for the foreseeable future.

新方法使用命名事件和用户定义的可调参数将活动与事件相关联。API的外观和感觉是由JQuery,Blinker和Hibernate等多种来源所驱动的,在几十个用户在Twitter上的会议中也进行了几次进一步的修改,这个用户似乎比邮件列表的响应率高得多这样的问题。

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

现在有几个系统构建在新的事件API上,包括新的“可变属性”API以及复合属性。对事件的强调也导致了一些新的事件的发生,包括属性到期和刷新操作,腌渍装载/倾倒操作,完成的映射器建造操作。

也可以看看

Events

#1902 T0>

混合属性,实现/取代synonym(),comparable_property()

“派生属性”的例子现在已经变成官方的扩展。synonym()的典型用例是提供对映射列的描述符访问; comparable_property()的用例应该能够从任何描述符中返回一个PropComparator在实践中,“派生”的方法更易于使用,更具可扩展性,在几十行纯Python中实现,几乎不需要导入,并且不需要ORM内核甚至不需要知道它。该功能现在称为“混合属性”扩展名。

synonym() and comparable_property() are still part of the ORM, though their implementations have been moved outwards, building on an approach that is similar to that of the hybrid extension, so that the core ORM mapper/query/property modules aren’t really aware of them otherwise.

也可以看看

Hybrid Attributes

#1903 T0>

速度增强

按照所有主要SQLA版本的惯例,通过内部广泛的传递来减少开销和呼叫数量,这进一步减少了常见场景中所需的工作。这个版本的亮点包括:

  • 对于主键已经存在的行,刷新过程现在将INSERT语句捆绑到提供给cursor.executemany()的批处理中。特别是,这通常适用于连接表继承配置上的“子表”,这意味着对于连接表对象的大批量插入,调用cursor.execute的次数可以减半,允许对传递给cursor.executemany()的语句进行本地DBAPI优化(例如重新使用预准备语句)。
  • 访问已加载的相关对象的多对一引用时调用的代码路径已大大简化。直接检查身份映射,而不需要首先生成一个新的Query对象,这在需要访问的数千个内存中的多对一的上下文中是昂贵的。构造的每个调用“加载器”对象也不再用于大多数惰性属性加载。
  • 当映射器内部访问flush内的映射属性时,组合的重写允许更短的代码路径。
  • 当“保存更新”和其他级联操作需要在与属性关联的数据成员的全部范围中级联时,新的内联属性访问功能取代了之前“历史”的使用。这减少了为这个速度关键操作生成一个新的History对象的开销。
  • 已经内联和简化了与执行语句相对应的ExecutionContext的内部结构。
  • 现在缓存每个语句执行的类型生成的bind_processor()result_processor()可调集(仔细,以避免ad-hoc类型和方言的内存泄漏)为了这种类型的生命周期,进一步减少了每个语句的调用开销。
  • 语句的特定Compiled实例的“绑定处理器”集合也缓存在Compiled对象上,进一步利用了flush进程重新使用INSERT,UPDATE,DELETE语句相同的编译形式。

包含样本基准脚本的callcount简化的演示在http://techspot.zzzeek.org/2010/12/12/a-tale-of-three - profiles /

复写重写

The “composite” feature has been rewritten, like synonym() and comparable_property(), to use a lighter weight implementation based on descriptors and events, rather than building into the ORM internals. 这允许从映射器/工作单元的内部消除一些延迟,并且简化了组合的工作。复合属性现在不再隐藏它所建立的基础列,现在它们保持为常规属性。复合材料还可以作为relationship()以及Column()属性的代理。

主要的向后不兼容的复合变化是他们不再使用mutable=True系统来检测就地突变。请使用突变跟踪扩展名来建立现有的组合使用情况的就地更改事件。

#2008 #2024

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

现在使用显式语句向目标发出query.join()的默认方法是:

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

在0.6中,这个用法被认为是一个错误,因为join()接受多个对应于多个JOIN子句的参数 - 两个参数形式需要在一个元组中以消除单参数和双参数连接目标。在0.6的中间,我们为这种特定的调用方式添加了检测和错误消息,因为它很常见。在0.7中,由于我们无论如何都在检测确切的模式,而且由于不得不无条件地键入元组是非常烦人的,所以非元组方法现在成为“正常”的方式。与单连接的情况相比,“多JOIN”的用例是非常罕见的,通过多次调用join()可以更清楚地表示多个连接。

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

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

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

查询连接

#1923 T0>

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

一个新的扩展Mutation Tracking提供了一种机制,通过该机制,用户定义的数据类型可以将改变事件提供给拥有的父亲或父母。The extension includes an approach for scalar database values, such as those managed by PickleType, postgresql.ARRAY, or other custom MutableType classes, as well as an approach for ORM “composites”, those configured using composite().

也可以看看

Mutation Tracking

NULLS FIRST / NULLS LAST运算符

These are implemented as an extension to the asc() and desc() operators, called nullsfirst() and nullslast().

#723 T0>

select.distinct(),query.distinct()接受PostgreSQL的* args DISTINCT ON

This was already available by passing a list of expressions to the distinct keyword argument of select(), the distinct() method of select() and Query now accept positional arguments which are rendered as DISTINCT ON when a Postgresql backend is used.

不同() T0>

Query.distinct() T0>

#1069 T0>

Index()可以内嵌在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__的好处,特别是在与mixin一起使用时:

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)

索引 T0>

窗口函数SQL构造

一个“窗口函数”提供了一个关于结果集生成的信息。这允许针对诸如“行号”,“等级”等的各种标准。已知它们至少被Postgresql,SQL Server和Oracle支持,可能还有其他的。

对窗口函数的最好的介绍在Postgresql的站点上,从8.4版本开始支持窗口函数:

http://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 T0>

#1844 T0>

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

这为单个Connection设置事务隔离级别,直到Connection被关闭,并且其基础DBAPI资源返回到连接池,隔离级别重置为默认。默认隔离级别是使用create_engine()isolation_level参数设置的。

事务隔离支持目前只支持Postgresql和SQLite后端。

execution_options() T0>

#2001 T0>

TypeDecorator works with integer primary key columns

扩展Integer行为的TypeDecorator可以与主键列一起使用。现在,Column的“自动增量”功能将认识到,底层数据库列仍然是一个整数,以便拉斯维加斯机制继续运行。The TypeDecorator itself will have its result value processor applied to newly generated primary keys, including those received by the DBAPI cursor.lastrowid accessor.

#2005 #2006

TypeDecorator is present in the “sqlalchemy” import space

不再需要从sqlalchemy.types中导入它,现在将它镜像到sqlalchemy中。

新方言

方言已被添加:

  • Drizzle数据库的MySQLdb驱动程序:

    细雨 T0>

  • 支持pymysql DBAPI:

    pymsql注释

  • psycopg2现在可以与Python 3一起使用

行为改变(向后兼容)

C扩展默认生成

这是0.7b4。如果检测到cPython 2.xx,exts将会生成。如果构建失败,例如在Windows安装中,则捕获该条件并继续进行非C安装。如果使用Python 3或Pypy,则C exts将不会生成。

Query.count()简化,应该几乎总是工作

Query.count()中发生的非常古老的猜测已被现代化以使用.from_self()That is, query.count() is now equivalent to:

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

以前,内部逻辑试图重写查询本身的列子句,并且在检测到“子查询”条件时(例如可能包含聚合的列查询或带有DISTINCT的查询)将经历复杂的重写列子句的过程。这个逻辑在复杂条件下失败了,特别是那些涉及到连接表继承的逻辑,并且被更全面的.from_self()调用所淘汰。

query.count()发出的SQL现在总是如下形式:

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

也就是说,原来的查询完全保留在子查询中,没有更多的猜测应该如何应用计数。

#2093 T0>

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

MySQL用户已经报道过,MyISAM引擎不会因为这个简单的改变而完全落空。请注意,对于无法处理简单子查询的DB进行优化的简单count()应该使用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子句现在使用绑定参数

LIMIT和OFFSET子句或其后端等价物(即TOP,ROW NUMBER OVER等),使用绑定参数作为实际值,支持它的所有后端(大部分除了Sybase)。这允许更好的查询优化器性能,因为具有不同LIMIT / OFFSET的多个语句的文本字符串现在是相同的。

#805 T0>

记录增强功能

Vinay Sajip为我们的日志记录系统提供了一个补丁,使得不再需要嵌入在引擎和池的日志语句中的“十六进制字符串”来允许echo标志正常工作。使用过滤日志记录对象的新系统允许我们保持当前的行为,即echo在单个引擎中是本地的,而不需要在这些引擎上附加本地的标识字符串。

#1926 T0>

简化的polymorphic_on赋值

The population of the polymorphic_on column-mapped attribute, when used in an inheritance scenario, now occurs when the object is constructed, i.e. its __init__ method is called, using the init event. 该属性的行为与任何其他列映射属性相同。以前,特殊逻辑会在刷新期间触发以填充此列,从而阻止任何用户代码修改其行为。新的方法通过三种方式改进了这一点:1.多态身份现在就在物体构建的时候出现在物体上; 2.多态身份可以被用户代码改变,而没有任何其他列映射属性的行为差异; 3.刷新过程中映射器的内部被简化,不再需要对此列进行特殊检查。

#1895 T0>

包含多个路径的contains_eager()链(即“all()”)

现在,`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 T0>

禁止没有父母的孤儿被允许

我们已经有一个长期的行为,在flush期间检查所谓的“孤立”,即与指定“delete-orphan”级联的relationship()关联的对象,已经被添加到会话中进行INSERT,并且没有建立父母关系。这个检查是在几年前添加的,以适应测试孤儿行为的一致性的一些测试案例。在现代SQLA中,这个检查在Python方面不再需要。通过使对象的父行的外键引用NOT NULL来完成“孤立检查”的等同行为,其中数据库以与SQLA允许大多数其他操作一样的方式建立数据一致性的工作。如果对象的父外键可以为空,则可以插入该行。当对象被一个特定的父对象持久化时,运行“孤立对象”行为,然后与该父对象关联,导致为其发出DELETE语句。

#1912 T0>

收集成员时产生的警告,标量指示不属于flush 的一部分

当前标记为“脏”的父对象上通过加载的relationship()引用的相关对象在当前Session中不存在时,现在会发出警告。

将对象添加到Session时,或者当对象首先与父对象关联时,save-update级联会生效,以便通常与对象相关的对象全部出现在同一个Session中。但是,如果针对特定的relationship()禁用save-update级联,则不会发生此行为,而刷新过程不会尝试对其进行更正,而是与配置的级联行为保持一致。以前,当在冲洗期间检测到这些物体时,它们被无声地跳过。新的行为是发出一个警告,目的是提醒那些经常出现意外行为的情况。

#1973 T0>

安装程序不再安装鼻插件

由于我们转向鼻子,我们使用了一个通过setuptools安装的插件,所以nosetests脚本会自动运行SQLA的插件代码,这是我们的测试需要一个完整的环境。在0.6的中间,我们意识到这里的导入模式意味着Nose的“coverage”插件会被打破,因为“coverage”要求在导入任何被覆盖的模块之前启动它。所以在0.6的中期,我们通过在构建中添加一个单独的sqlalchemy-nose包来解决这个问题,从而使情况变得更糟。

In 0.7 we’ve done away with trying to get nosetests to work automatically, since the SQLAlchemy module would produce a large number of nose configuration options for all usages of nosetests, not just the SQLAlchemy unit tests themselves, and the additional sqlalchemy-nose install was an even worse idea, producing an extra package in Python environments. 0.7中的sqla_nose.py脚本现在是用鼻子运行测试的唯一方法。

#1949 T0>

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 T0>

aliased()接受FromClause元素

This is a convenience helper such that in the case a plain FromClause, such as a select, Table or join is passed to the orm.aliased() construct, it passes through to the .alias() method of that from construct rather than constructing an ORM level AliasedClass.

#2018 T0>

Session.connection(),Session.execute()接受'bind'

这是为了允许执行/连接操作明确地参与引擎的公开事务。It also allows custom subclasses of Session that implement their own get_bind() method and arguments to use those custom arguments with both the execute() and connection() methods equally.

Session.connection Session.execute

#1996 T0>

独立地绑定column子句中的参数auto-labeled。

现在在选择的“列子句”中出现的绑定参数现在被自动标记为与其他“匿名”子句一样,除了别的以外,当行被提取时允许它们的“类型”是有意义的,如结果行处理器中那样。

SQLite - 相对文件路径通过os.path.abspath()来标准化

这样一来,更改当前目录的脚本将继续定位到相同的位置,因为建立了后续的SQLite连接。

#2036 T0>

MS-SQL - String/Unicode/VARCHAR/NVARCHAR/VARBINARY emit “max” for no length

在MS-SQL后端,当没有指定长度时,字符串/ Unicode类型及其对应的VARCHAR / NVARCHAR以及VARBINARY(#1833)发出“max”作为长度。这使得它与Postgresql的VARCHAR类型更兼容,在没有指定长度的情况下,它类似地是无界的。当没有指定长度时,SQL Server将这些类型的长度默认为“1”。

行为改变(向后不相容)

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

PickleType和ARRAY可变性默认关闭

当映射具有PickleTypepostgresql.ARRAY数据类型的列时,此更改引用ORM的默认行为。mutable标志现在默认设置为False如果现有的应用程序使用这些类型,并且依赖于就地变化的检测,则必须使用mutable=True构造类型对象以恢复0.6行为:

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

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

mutable=True标志正在被淘汰,有利于新的突变跟踪扩展。该扩展提供了一种机制,通过该机制,用户定义的数据类型可以将改变事件提供给拥有的父母或父母。

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

Existing applications which use PickleType, postgresql.ARRAY or other MutableType subclasses, and require in-place mutation detection, should migrate to the new mutation tracking system, as mutable=True is likely to be deprecated in the future.

#1980 T0>

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

所谓的“复合”映射属性(使用复合列类型中描述的技术配置的属性)已经被重新实现,使得ORM内部不再意识到它们(导致更短和更高效代码路径在关键部分)。虽然复合类型通常被认为是不可变的值对象,但是从未被强制执行。对于使用具有可变性的组合的应用程序,Mutation Tracking扩展提供了一个基类,它为用户定义的组合类型建立一个机制,将更改事件消息发送回每个对象的父项或父项。

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

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

This change is 99.999% backwards compatible, unless you are using temporary tables across connection pool connections.

基于文件的SQLite连接速度非常快,使用NullPool意味着每次调用Engine.connect都会创建一个新的pysqlite连接。

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

SingletonThreadPool is still the default engine when a :memory: database is used.

请注意,由于SQLite处理临时表的方式,此更改会中断跨Session提交使用的临时表如果希望超出一个池连接范围的临时表,请参见http://www.sqlalchemy.org/docs/dialects_sqlite.html#using - temporary-tables-with-sqlite中的注释。

#1921 T0>

Session.merge() checks version ids for versioned mappers

Session.merge()将检查传入状态的版本ID与数据库的版本ID,假定映射使用版本ID并且传入状态具有分配的版本ID,并且如果它们不匹配则引发StaleDataError。这是正确的行为,因为如果传入状态包含陈旧的版本ID,则应假定状态为陈旧。

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

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

#2027 T0>

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

对于依赖旧行为的应用程序来说,这种改进可能略微向后兼容。

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

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

qu = qa.union(qb)

qu产生的单列的名称将是spam以前它会像foo_spam那样,因为union会组合东西,这与spam名称不一致未结合的查询。

#1942 T0>

映射列属性首先引用最具体的列

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

使用声明,情况是这样的:

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 - 这是由于属性。If it were named differently on the class, such as Child.child_id, it then maps distinctly to child.id, with Child.id being the same attribute as Parent.id.

当使用id属性引用parent.idchild.id时,它将它们存储在一个有序列表中。Child.id这样的表达式在渲染时就指向这些列的一个直到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本地的任何其他属性的行为。The with_polymorphic() method, or a similar strategy of explicitly joining the underlying Table objects, is used to render a query against all Parent objects with criteria against Child, in the same manner as that of 0.5 and 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

此更改的另一个影响是跨两个表的联合继承负载将从子表的值中填充,而不是父表的值。一个不常见的情况是,使用with_polymorphic="*"对“父”进行的查询针对“父”发出查询,并且将“LEFT OUTER JOIN”设置为“child”。该行位于“Parent”中,看到多态标识对应于“Child”,但假设“child”中的实际行已被删除由于这种损坏,行来与“孩子”对应的所有列设置为NULL - 这是现在填充的值,而不是父表中的一个。

#1892 T0>

映射到两个或多个同名列的连接需要显式声明

这与#1892中的前一个更改有些相关。当映射到连接时,同名列必须显式链接到映射属性,即如根据多个表映射类所述。

给定两个表foobar,每个表具有主键列id,现在会产生一个错误:

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

This because the mapper() refuses to guess what column is the primary representation of FooBar.id - is it foo.c.id or is it 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 T0>

Mapper要求polymorphic_on列存在于映射的可选

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

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

where above the polymorphic_on needs to be on a sometable column, in this case perhaps sometable.c.some_lookup_id. 也有一些“多态联盟”的情况,有时会出现类似的错误。

这样的配置错误一直是“错误的”,并且上面的映射不能像指定的那样工作 - 列将被忽略。然而,在罕见的情况下,应用程序已经在不知不觉中依赖于这种行为,这可能是向后不相容的。

#1875 T0>

DDL()结构现在转义了百分号

Previously, percent signs in DDL() strings would have to be escaped, i.e. %% depending on DBAPI, for those DBAPIs that accept pyformat or format binds (i.e. psycopg2, mysql-python), which was inconsistent versus text() constructs which did this automatically. 对于text(),现在对DDL()进行相同的转义。

#1897 T0>

Table.c / MetaData.tables细化了一下,不允许直接变异

Another area where some users were tinkering around in such a way that doesn’t actually work as expected, but still left an exceedingly small chance that some application was relying upon this behavior, the construct returned by the .c attribute on Table and the .tables attribute on MetaData is explicitly non-mutable. 构造的“可变”版本现在是私人的。Adding columns to .c involves using the append_column() method of Table, which ensures things are associated with the parent Table in the appropriate way; similarly, MetaData.tables has a contract with the Table objects stored in this dictionary, as well as a little bit of new bookkeeping in that a set() of all schema names is tracked, which is satisfied only by using the public Table constructor as well as Table.tometadata().

当然有可能这些属性所咨询的ColumnCollectiondict集合有一天可能在其所有的突变方法上实现事件,这样恰当的簿记就会发生集合,但是直到有人有动机去实现所有这些以及数十个新的单元测试,缩小这些集合的变异路径将确保没有应用程序试图依赖当前不被支持的用法。

#1893 #1917

对于所有的inserted_primary_key值,server_default始终返回None

在Integer PK列上存在server_default时建立一致性。SQLA不会预取这些,也不会返回到cursor.lastrowid(DBAPI)中。确保所有后端始终在result.inserted_primary_key中返回None,这些后端可能先前返回了一个值。在主键列上使用server_default是非常不寻常的。如果使用特殊函数或SQL表达式来生成主键默认值,则应该将其设置为Python端“default”而不是server_default。

关于这种情况的反思,除了在我们检测到序列默认值的PG SERIAL col的情况下,对server_default的int PK col的反映将“autoincrement”标志设置为False。

#2020 #2021

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

For a few years we’ve added the string sqlalchemy.exceptions to sys.modules, so that a statement like “import sqlalchemy.exceptions” would work. The name of the core exceptions module has been exc for a long time now, so the recommended import for this module is:

from sqlalchemy import exc

The exceptions name is still present in “sqlalchemy” for applications which might have said from sqlalchemy import exceptions, but they should also start using the exc name.

查询计时配方更改

虽然不是SQLAlchemy本身的一部分,但值得一提的是,将ConnectionProxy重写到新的事件系统意味着它不再适合“定时查询”配方。请调整查询计时器以使用更新后的配方UsageRecipes / Profiling中显示的before_cursor_execute()after_cursor_execute()事件。

弃用的API

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

IntegerDate等简单类型在核心类型模块中不接受参数。The default constructor that accepts/ignores a catchall \*args, \**kwargs is restored as of 0.7b4/0.7.0, but emits a deprecation warning.

如果参数正在与像Integer这样的核心类型一起使用,那么可能是您打算使用特定于方言的类型,如sqlalchemy.dialects.mysql.INTEGER接受例如“display_width”参数。

compile_mappers()重命名为configure_mappers(),简化了内部配置

这个系统慢慢地从小的东西变成了东西,变成了局部的东西,变成了一个单独的映射器,而且这个系统很难被命名为全局的“注册表”级别函数,而且命名得不好,所以我们通过将实现移出Mapper,并将其重命名为configure_mappers()当应用程序通过属性或查询访问需要映射时,通常根本不需要调用configure_mappers(),因为这个过程是在需要的基础上进行的。

#1966 T0>

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

PoolListener, ConnectionProxy, DDLElement.execute_at are superseded by event.listen(), using the PoolEvents, EngineEvents, DDLEvents dispatch targets, respectively.

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

MapperExtension, AttributeExtension, SessionExtension are superseded by event.listen(), using the MapperEvents/InstanceEvents, AttributeEvents, SessionEvents, dispatch targets, respectively.

在select()中为MySQL发送字符串“distinct”应该通过前缀

这个模糊的特性允许这种模式与MySQL后端:

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

prefixes关键字或prefix_with()方法应该用于非标准或不寻常的前缀:

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

useexisting取代extend_existingkeep_existing

表中的useexisting标志被一对新的标志keep_existingextend_existing所取代。extend_existing is equivalent to useexisting - the existing Table is returned, and additional constructor elements are added. 使用keep_existing,将返回现有表,但不会添加其他构造函数元素 - 仅在新创建表时应用这些元素。

向后不兼容的API更改

可传递给bindparam()的可调参数不会被评估 - 影响Beaker示例

#1950 T0>

请注意,这将影响Beaker缓存示例,其中_params_from_query()函数的工作需要稍作调整。如果您使用Beaker示例中的代码,则应该应用此更改。

types.type_map现在是private,types._type_map

我们注意到一些用户使用sqlalchemy.types中的这个字典作为关联Python类型与SQL类型的捷径。我们无法保证本字典的内容或格式,另外,以一对一的方式关联Python类型的业务有一些灰色区域,最好由各个应用程序决定,所以我们已经强调了这个属性。

#1870 T0>

将独立alias()函数的alias关键字arg重命名为name

This so that the keyword argument name matches that of the alias() methods on all FromClause objects as well as the name argument on 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() -> removed, was not used

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

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

SingletonThreadPool.cleanup() - > _cleanup()

SingletonThreadPool.dispose_local() - >删除,使用conn.invalidate()

#1982 T0>

先前已弃用,现已删除

Query.join(),Query.outerjoin(),eagerload(),eagerload_all()等不再允许属性列表作为参数

将属性或属性名称传递给Query.joineagerload()

# 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被删除

This feature provided a mapper extension which linked class- based functionality with a particular ScopedSession, in particular providing the behavior such that new object instances would be automatically associated with that session. 该功能被教程和框架过度使用,由于其隐含的行为导致很大的用户混淆,并在0.5.5中被弃用。用于复制其功能的技术在[wiki:UsageRecipes / SessionAwareMapper]