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

SQLAlchemy 1.1文档

SQLAlchemy 0.6有什么新东西?

关于本文档

本文档介绍了2012年5月5日发布的SQLAlchemy版本0.5(2010年1月16日发布)和SQLAlchemy 0.6版本之间的更改。

文件日期:2010年6月6日

本指南记录了影响用户将其应用程序从0.5系列SQLAlchemy迁移到0.6的API更改。请注意,SQLAlchemy 0.6删除了在0.5系列整个范围内被弃用的一些行为,也弃用了更多的特定于0.5的行为。

平台支持

  • 整个2.xx系列的cPython 2.4以上版本
  • Jython 2.5.1 - 使用Jython中包含的zxJDBC DBAPI。
  • cPython 3.x - 参见[source:sqlalchemy / trunk / README.py3k]了解如何为python3构建信息。

新的方言系统

现在,方言模块在单个数据库后端的范围内分解成不同的子组件。方言实现现在在sqlalchemy.dialects包中。sqlalchemy.databases包依然以占位符的形式存在,为简单的导入提供一定程度的后向兼容性。

对于每个受支持的数据库,在包含多个文件的sqlalchemy.dialects中存在一个子包。每个包都包含一个名为base.py的模块,它定义了该数据库使用的特定SQL方言。它还包含一个或多个“驱动程序”模块,每个模块对应一个特定的DBAPI - 这些文件被命名为与DBAPI本身相对应,如pysqlitecx_oracle pyodbcSQLAlchemy方言使用的类首先在base.py模块中声明,定义数据库定义的所有行为特征。这些包括能力映射,如“支持序列”,“支持返回”等,类型定义和SQL编译规则。每个“驱动程序”模块依次提供这些类的子类,以覆盖默认行为以适应该DBAPI的附加功能,行为和怪癖。对于支持多个后端的DBAPI(pyodbc,zxJDBC,mxODBC),方言模块将使用sqlalchemy.connectors包中的mixins,它提供所有后端通用的DBAPI功能,通常处理连接参数。这意味着使用pyodbc,zxJDBC或mxODBC进行连接(实现时)在支持的后端是非常一致的。

create_engine()使用的URL格式已经增强,可以使用受JDBC启发的方案来处理特定后端的任意数量的DBAPI。以前的格式仍然有效,并且会选择一个“默认的”DBAPI实现,比如下面的Postgresql URL将使用psycopg2:

create_engine('postgresql://scott:tiger@localhost/test')

但是,要指定特定的DBAPI后端(如pg8000),请使用加号“+”将其添加到URL的“协议”部分:

create_engine('postgresql+pg8000://scott:tiger@localhost/test')

重要的方言链接:

关于方言的其他说明:

  • 在SQLAlchemy 0.6中,类型系统已经发生了巨大的变化。这对所有有关命名约定,行为和实现的方言都有影响。请参阅下面“类型”一节。
  • the ResultProxy object now offers a 2x speed improvement in some cases thanks to some refactorings.
  • the RowProxy, i.e. individual result row object, is now directly pickleable.
  • 用于定位外部方言的setuptools入口点现在称为sqlalchemy.dialects用0.4或0.5写的外部方言在任何情况下都需要修改为0.6,所以这个改变不会增加任何额外的困难。
  • 方言现在在初始连接上接收一个initialize()事件来确定连接属性。
  • 编译器生成的函数和运算符现在使用形式为“visit_ ”和“visit_ _fn”的(几乎)常规调度函数来提供定制的处理。 T1> T0>这代替了在编译器子类中使用简单的访问者方法复制“函数”和“操作符”字典的需要,并且还允许编译器子类完全控制渲染,因为完整的_Function或_BinaryExpression对象被传入。

Dialect Imports

方言的进口结构发生了变化。现在,每种方言都通过sqlalchemy.dialects.<name>导出其基本“方言”类以及该方言所支持的全套SQL类型。例如,要导入一组PG类型:

from sqlalchemy.dialects.postgresql import INTEGER, BIGINT, SMALLINT,\
                                            VARCHAR, MACADDR, DATE, BYTEA

Above, INTEGER is actually the plain INTEGER type from sqlalchemy.types, but the PG dialect makes it available in the same way as those types which are specific to PG, such as BYTEA and MACADDR.

表达式语言变化

一个重要的表达语言Gotcha

对于可能影响某些应用程序的表达式语言,有一个相当重要的行为改变。Python布尔表达式的布尔值,即==!=以及类似的,现在可以精确地评估被比较的两个子对象。

我们知道,将一个ClauseElement与任何其他对象进行比较都会返回另一个ClauseElement

>>> from sqlalchemy.sql import column
>>> column('foo') == 5
<sqlalchemy.sql.expression._BinaryExpression object at 0x1252490>

这使得Python表达式在转换为字符串时产生SQL表达式:

>>> str(column('foo') == 5)
'foo = :foo_1'

但是,如果我们这样说呢?

>>> if column('foo') == 5:
...     print("yes")
...

在以前版本的SQLAlchemy中,返回的_BinaryExpression是一个普通的Python对象,其计算结果为True现在它计算实际的ClauseElement是否应该与被比较的哈希值相同。含义:

>>> bool(column('foo') == 5)
False
>>> bool(column('foo') == column('foo'))
False
>>> c = column('foo')
>>> bool(c == c)
True
>>>

这意味着代码如下:

if expression:
    print("the expression is:", expression)

如果expression是二进制子句,则不会进行评估。由于不应该使用上述模式,所以如果在布尔上下文中调用,基ClauseElement现在会引发异常:

>>> bool(c)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  ...
    raise TypeError("Boolean value of this clause is not defined")
TypeError: Boolean value of this clause is not defined

要检查ClauseElement表达式的代码应改为:

if expression is not None:
    print("the expression is:", expression)

请记住,这也适用于表和列对象

改变的理由是双重的:

  • Comparisons of the form if c1 == c2: <do something> can actually be written now
  • 支持ClauseElement对象的正确哈希现在可以在其他平台上运行,即Jython。直到这一点SQLAlchemy严重依赖于cPython在这方面的具体行为(并且偶尔还有问题)。

更严格的“executemany”行为

SQLAlchemy中的“executemany”对应于对execute()的调用,传递一组绑定参数集合:

connection.execute(table.insert(), {'data':'row1'}, {'data':'row2'}, {'data':'row3'})

Connection对象发送给定的用于编译的insert()结构时,它将传递给第一组绑定的键名传递给编译器,语句的VALUES子句。熟悉这个构造的用户将会知道其余字典中的其他键没有任何影响。What’s different now is that all subsequent dictionaries need to include at least every key that is present in the first dictionary. 这意味着像这样的调用不再有效:

connection.execute(table.insert(),
                        {'timestamp':today, 'data':'row1'},
                        {'timestamp':today, 'data':'row2'},
                        {'data':'row3'})

因为第三行没有指定'timestamp'列。先前版本的SQLAlchemy只会为这些缺失的列插入NULL。但是,如果上面示例中的timestamp列包含Python方面的默认值或函数,那么将使用而不是这是因为“executemany”操作是针对大量参数集的最大性能进行了优化的,并没有试图为这些丢失的键计算Python方面的默认值。由于缺省值通常是作为与INSERT语句嵌入的SQL表达式来实现的,或者是基于INSERT字符串的结构触发的服务器端表达式,它们根据定义不能根据每个参数集有条件地触发,将不一致的Python方面默认行为与SQL /服务器端默认值不同。(基于SQL表达式的默认设置是嵌入到0.5系列中,再次将大量参数集的影响降至最低)。

SQLAlchemy 0.6因此通过禁止任何后续参数集将任何字段留空来建立可预测的一致性。这样,Python方面的默认值和函数就不会再有沉默的失败,这些失败在SQL和服务器端的默认设置中可以保持一致。

UNION和其他“复合”结构一致地加上括号

A rule that was designed to help SQLite has been removed, that of the first compound element within another compound (such as, a union() inside of an except_()) wouldn’t be parenthesized. 这是不一致的,并且在Postgresql上产生错误的结果,PostgreSQL有关于INTERSECTION的优先规则,而且通常是一个惊喜。在使用SQLite复杂的组合时,现在需要将第一个元素转换为子查询(也与PG兼容)。一个新的例子是在[http://www.sqlalchemy.org/docs/06/sqlexpression.html#联合和其他集操作]结尾的SQL表达式教程中。有关更多背景信息,请参阅#1665和r6690。

C用于结果获取的扩展

The ResultProxy and related elements, including most common “row processing” functions such as unicode conversion, numerical/boolean conversions and date parsing, have been re-implemented as optional C extensions for the purposes of performance. This represents the beginning of SQLAlchemy’s path to the “dark side” where we hope to continue improving performance by reimplementing critical sections in C. The extensions can be built by specifying --with-cextensions, i.e. python setup.py --with- cextensions install.

The extensions have the most dramatic impact on result fetching using direct ResultProxy access, i.e. that which is returned by engine.execute(), connection.execute(), or session.execute(). 在由ORM Query对象返回的结果中,结果提取的开销比例不高,所以ORM性能提高得更为温和,主要是提取大型结果集。性能改进高度依赖于使用的dbapi和用于访问每行的列的语法(例如,row['name']row.name当前的扩展对插入/更新/删除的速度没有影响,也没有提高SQL执行的延迟,也就是说,花费大量时间执行很多语句的应用程序的结果集很少,看起来并没有太大的改进。

无论扩展名为0.6,0.5的性能都有所提高。A quick overview of what connecting and fetching 50,000 rows looks like with SQLite, using mostly direct SQLite access, a ResultProxy, and a simple mapped ORM object:

sqlite select/native: 0.260s

0.6 / C extension

sqlalchemy.sql select: 0.360s
sqlalchemy.orm fetch: 2.500s

0.6 / Pure Python

sqlalchemy.sql select: 0.600s
sqlalchemy.orm fetch: 3.000s

0.5 / Pure Python

sqlalchemy.sql select: 0.790s
sqlalchemy.orm fetch: 4.030s

在上面,由于Python中的性能增强,ORM获取行比0.5快33%。有了C扩展,我们又得到了20%。However, ResultProxy fetches improve by 67% with the C extension versus not. 其他测试报告,对于某些情况(例如发生大量字符串转换的情况),速度提高了200%。

新的模式功能

sqlalchemy.schema包得到了一些长期需要的关注。最明显的变化是新扩展的DDL系统。在SQLAlchemy中,从版本0.5开始,可以创建自定义DDL字符串,并将它们与表或元数据对象相关联:

from sqlalchemy.schema import DDL

DDL('CREATE TRIGGER users_trigger ...').execute_at('after-create', metadata)

现在,全套的DDL结构可以在同一个系统下使用,包括CREATE TABLE,ADD CONSTRAINT等。:

from sqlalchemy.schema import Constraint, AddConstraint

AddContraint(CheckConstraint("value > 5")).execute_at('after-create', mytable)

另外,所有的DDL对象现在都是像任何其他SQLAlchemy表达式对象一样的ClauseElement对象:

from sqlalchemy.schema import CreateTable

create = CreateTable(mytable)

# dumps the CREATE TABLE as a string
print(create)

# executes the CREATE TABLE statement
engine.execute(create)

并使用sqlalchemy.ext.compiler扩展名,您可以创建自己的:

from sqlalchemy.schema import DDLElement
from sqlalchemy.ext.compiler import compiles

class AlterColumn(DDLElement):

    def __init__(self, column, cmd):
        self.column = column
        self.cmd = cmd

@compiles(AlterColumn)
def visit_alter_column(element, compiler, **kw):
    return "ALTER TABLE %s ALTER COLUMN %s %s ..." % (
        element.column.table.name,
        element.column.name,
        element.cmd
    )

engine.execute(AlterColumn(table.c.mycolumn, "SET DEFAULT 'test'"))

已弃用/已删除模式元素

模式包也大大简化了。在0.5中被弃用的许多选项和方法已被删除。其他鲜为人知的访问器和方法也被删除。

  • “所有者”关键字参数将从Table中删除。使用“模式”来表示任何名称空间要预先添加到表名称。
  • 不推荐使用MetaData.connect()ThreadLocalMetaData.connect() - 发送“绑定”属性来绑定元数据。
  • 不推荐使用metadata.table_iterator()方法(使用sorted_tables)
  • the “metadata” argument is removed from DefaultGenerator and subclasses, but remains locally present on Sequence, which is a standalone construct in DDL.
  • 弃用PassiveDefault - 使用DefaultClause
  • IndexConstraint对象中删除了公共可变性:
    • ForeignKeyConstraint.append_element()
    • Index.append_column()
    • UniqueConstraint.append_column()
    • PrimaryKeyConstraint.add()
    • PrimaryKeyConstraint.remove()

这些应该以声明方式构建(即在一个构建中)。

  • 其他删除的东西:
    • Table.key(不知道这是什么)
    • Column.bind(通过column.table.bind获取)
    • Column.metadata(通过column.table.metadata获取)
    • Column.sequence(使用column.default)

其他行为改变

  • UniqueConstraint, Index, PrimaryKeyConstraint all accept lists of column names or column objects as arguments.
  • ForeignKey上的use_alter标志现在是可以使用DDL()事件系统手动构建的操作的快捷选项。A side effect of this refactor is that ForeignKeyConstraint objects with use_alter=True will not be emitted on SQLite, which does not support ALTER for foreign keys. 这对SQLite的行为没有影响,因为SQLite实际上并没有兑现FOREIGN KEY约束。
  • Table.primary_key不可分配 - 使用table.append_constraint(PrimaryKeyConstraint(...))
  • 带有ForeignKeyColumn定义,并且没有类型,例如Column(name, ForeignKey(sometable.c.somecol)) used to get the type of the referenced column. 现在支持自动类型推断是部分的,可能不适用于所有情况。

记录打开了

在这里和那里的一些额外的方法调用的代价,你可以在引擎,池或映射器创建后设置INFO和DEBUG的日志级别,并开始记录。The isEnabledFor(INFO) method is now called per-Connection and isEnabledFor(DEBUG) per-ResultProxy if already enabled on the parent connection. 池日志记录发送到log.info()log.debug()没有检查 - 注意池检出/签入通常每个事务一次。

反射/督察API

反射系统允许通过Table('sometable', 元数据, autoload = True)反射表格列 t0 >已经被开放到自己的细粒度API中,允许直接检查数据库元素,比如表,列,约束,索引等等。此API将返回值表示为字符串,字典和TypeEngine对象的简单列表。现在autoload=True的内部建立在这个系统上,原始数据库信息到sqlalchemy.schema结构的转换是集中的,大大简化了个别方言的契约减少不同后端之间的错误和不一致。

要使用检查员:

from sqlalchemy.engine.reflection import Inspector
insp = Inspector.from_engine(my_engine)

print(insp.get_schema_names())

the from_engine() method will in some cases provide a backend-specific inspector with additional capabilities, such as that of Postgresql which provides a get_table_oid() method:

my_engine = create_engine('postgresql://...')
pg_insp = Inspector.from_engine(my_engine)

print(pg_insp.get_table_oid('my_table'))

返回支持

现在,insert()update()delete()结构支持returning()方法对应于由Postgresql,Oracle,MS-SQL和Firebird支持的SQL RETURNING子句。目前不支持任何其他后端。

以与select()结构相同的方式给出列表达式的列表,这些列的值将作为常规结果集返回:

result = connection.execute(
            table.insert().values(data='some data').returning(table.c.id, table.c.timestamp)
        )
row = result.first()
print("ID:", row['id'], "Timestamp:", row['timestamp'])

在四个受支持的后端之间执行RETURNING的方式差异很大,在Oracle需要复杂地使用OUT参数的情况下,这些参数被重新路由到“模拟”结果集中,而在MS-SQL使用尴尬的SQL语法的情况下。返回的使用受到限制:

  • 它不适用于任何“executemany()”执行风格。这是所有支持的DBAPI的限制。
  • 有些后端(如Oracle)只支持返回单行的RETURNING,这包括UPDATE和DELETE语句,这意味着update()或delete()构造必须只匹配一行,否则会引发错误(由Oracle提供,而不是SQLAlchemy的)。

RETURNING也被SQLAlchemy自动使用(当可用时,以及当没有另外通过显式的returning()调用指定)时,为单行INSERT语句获取新生成的主键值。这意味着对于需要主键值的插入语句,没有更多的“SELECT nextval(sequence)”预执行。真相被告知,隐式RETURNING特性确实比旧的“select nextval()”系统带来了更多的方法开销,它使用了一个快速而脏的cursor.execute()来获取序列值,而在Oracle需要额外的绑定的输出参数。因此,如果方法/协议开销比额外的数据库往返更昂贵,则可以通过将implicit_returning=False指定为create_engine()来禁用该功能。

键入系统更改

新Archicture

类型系统已经完全在幕后重新编制,以提供两个目标:

  • 从类型本身的SQL规范中分离对绑定参数和结果行值(通常是DBAPI要求)的处理,这是数据库要求。这与将数据库SQL行为与DBAPI分离的整体方言重构是一致的。
  • 根据TypeEngine对象建立清晰一致的契约,并基于列反射构建TypeEngine对象。

这些变化的重点包括:

  • 方言内部类型的建设已经全面检修。方言现在将公共可用类型定义为大写字母名称,而内部实现类型使用下划线标识符(即私人)。用SQL和DDL表示类型的系统已经被移至编译器系统。这样做的结果是大多数方言中的类型对象数量要少得多。关于这种方言作者的体系结构的详细文档在[source:/ lib / sqlalc hemy / dialects_type_migration_guidelines.txt]中。
  • 类型的反射现在返回types.py中的确切的UPPERCASE类型,或者如果类型不是标准的SQL类型,则返回方言本身的UPPERCASE类型。这意味着反射现在返回关于反射类型的更准确的信息。
  • 用户定义的TypeEngine类型,并希望提供get_col_spec()的类型现在应该是UserDefinedType的子类。
  • 所有类型的result_processor()方法现在接受一个额外的参数coltype这是附加到cursor.description的DBAPI类型对象,应在适用时使用,以便更好地决定返回哪种结果处理可调用对象。理想情况下,结果处理器功能永远不需要使用isinstance(),这是一个昂贵的调用。

本机Unicode模式

由于更多的DBAPI支持直接返回Python unicode对象,因此现在基本方言会对第一个连接进行检查,该连接确定DBAPI是否返回Python unicode对象,以便基本选择VARCHAR值。如果是这样,String类型和所有的子类(即TextUnicode等)将在收到结果行时跳过“unicode”检查/转换步骤。这为大型结果集提供了显着的性能提升。目前已知的“unicode模式”可用于:

  • sqlite3 / pysqlite
  • psycopg2 - SQLA 0.6现在在每个psycopg2连接对象上默认使用“UNICODE”类型扩展
  • pg8000
  • cx_oracle(我们使用输出处理器 - 很好的功能!)

其他类型可以根据需要选择禁用unicode处理,例如与MS-SQL一起使用时的NVARCHAR类型。

特别是,如果基于先前返回非Unicode字符串的DBAPI移植应用程序,则“本机unicode”模式具有明显不同的默认行为 - 声明为StringVARCHAR现在默认返回unicode,而之前它们会返回字符串。这可以打破预期非Unicode字符串的代码。通过将use_native_unicode=False传递给create_engine(),可以禁用psycopg2“native unicode”模式。

显式地不需要unicode对象的字符串列的更一般的解决方案是使用将unicode转换回utf-8或任何所需的TypeDecorator

class UTF8Encoded(TypeDecorator):
    """Unicode type which coerces to utf-8."""

    impl = sa.VARCHAR

    def process_result_value(self, value, dialect):
        if isinstance(value, unicode):
            value = value.encode('utf-8')
        return value

请注意,assert_unicode标志现在已被弃用。SQLAlchemy允许DBAPI和后端数据库在可用时处理Unicode参数,并且不会通过检查传入类型来增加操作开销;像sqlite和Postgresql这样的现代系统,如果传递了无效的数据,它们将在其末尾产生编码错误。在SQLAlchemy确实需要强制将Python的Unicode绑定参数转换为编码字符串,或者明确使用Unicode类型的情况下,如果对象是字符串,则会引发警告。这个警告可以使用Python警告过滤器(http://docs.python.org/library/warnings.html)来记录或者转换成一个异常。http://docs.python.org/library/warnings.html

通用枚举类型

我们现在在types模块中有一个Enum这是一个字符串类型,它被赋予了一系列“标签”,这些标签约束了给这些标签赋予的可能值。默认情况下,此类型使用最大标签的大小生成VARCHAR,并将CHECK约束应用于CREATE TABLE语句中的表。当使用MySQL时,默认的类型使用MySQL的ENUM类型,当使用Postgresql时,类型将使用CREATE TYPE &lt; mytype&gt; tt4> ENUM为了使用Postgresql创建类型,必须给构造函数指定name参数。该类型还接受native_enum=False选项,该选项将为所有数据库发出VARCHAR / CHECK策略。请注意,Postgresql ENUM类型目前不能与pg8000或zxjdbc一起使用。

反射返回方言特定类型

反射现在返回数据库中可能的最具体的类型。也就是说,如果使用String创建表,然后将其反射回来,则反射列可能是VARCHAR对于支持更具体形式的方言,这就是你会得到的。所以一个Text类型会在Oracle上回到oracle.CLOB,一个LargeBinary可能是一个mysql.MEDIUMBLOB等等这里的明显优势是反射保留了数据库必须说明的尽可能多的信息。

一些在表格元数据中大量使用的应用程序可能希望比较所反映的表格和/或未反映的表格中的类型。TypeEngine上有一个叫做_type_affinity的半隐私访问器,还有一个关联的比较帮助器_compare_type_affinity这个访问器返回类型对应的“generic”types类:

>>> String(50)._compare_type_affinity(postgresql.VARCHAR(50))
True
>>> Integer()._compare_type_affinity(mysql.REAL)
False

其他API更改

通常的“通用”类型仍然是使用中的一般系统,即StringFloatDateTime那里有一些变化:

  • 类型不再对默认参数进行猜测。In particular, Numeric, Float, as well as subclasses NUMERIC, FLOAT, DECIMAL don’t generate any length or scale unless specified. 这也继续包含有争议的StringVARCHAR类型(尽管当MySQL被要求渲染VARCHAR的时候,方言会先发制人)。假设没有默认值,并且如果在CREATE TABLE语句中使用它们,则如果底层数据库不允许这些类型的非长期版本,则会引发错误。
  • 对于BLOB / BYTEA /类似的类型,Binary类型已被重命名为LargeBinary对于BINARYVARBINARY,那些直接存在于types.BINARYtypes.VARBINARY MySQL和MS-SQL方言。
  • PickleType now uses == for comparison of values when mutable=True, unless the “comparator” argument with a comparison function is specified to the type. 如果你正在酸洗一个自定义对象,你应该实现一个__eq__()方法,以便基于值的比较是准确的。
  • Numeric和Float的默认“precision”和“scale”参数已被删除,现在默认为None。除非提供了这些值,否则NUMERIC和FLOAT默认情况下不带数字参数。
  • SQLite上的DATE,TIME和DATETIME类型现在可以使用可选的“storage_format”和“regexp”参数。可以使用“storage_format”来使用自定义字符串格式来存储这些类型。“regexp”允许使用自定义正则表达式来匹配数据库中的字符串值。
  • 不再支持SQLite TimeDateTime类型的__legacy_microseconds__类型。您应该使用新的“storage_format”参数。
  • DateTime types on SQLite now use by a default a stricter regular expression to match strings from the database. 如果您使用以旧格式存储的数据,请使用新的“regexp”参数。

ORM更改

将ORM应用程序从0.5升级到0.6应该几乎不需要更改,因为ORM的行为几乎完全相同。有一些默认的参数和名称的变化,一些加载行为已经改进。

新工作单元

The internals for the unit of work, primarily topological.py and unitofwork.py, have been completely rewritten and are vastly simplified. 这应该对使用没有任何影响,因为在刷新过程中所有现有的行为都已经完全保持(或者至少在我们的测试套件和少量生产环境经过严格测试的情况下)。flush()的性能现在使用少20-30%的方法调用,并且应该使用更少的内存。现在应该很容易地遵循源代码的意图和流程,并且在这一点上flush的结构是相当开放的,为潜在的新的复杂领域创造空间。刷新过程不再依赖于递归,因此可以刷新任意大小和复杂度的刷新计划。此外,映射程序的“保存”过程(它发出INSERT和UPDATE语句)现在缓存两个语句的“编译”形式,以便通过非常大的刷新进一步显着减少callcounts。

在使用flush或早期版本的0.6或0.5时,观察到的任何行为变化都应尽快报告给我们 - 我们将确保没有任何功能丢失。

query.update()query.delete() 的更改

  • query.update()的'expire'选项已被重命名为'fetch',因此与query.delete()
  • query.update() and query.delete() both default to ‘evaluate’ for the synchronize strategy.
  • update()和delete()的“同步”策略在失败时引发错误。没有隐含的回退到“取”。评估失败是基于标准的结构,所以成功/失败是基于代码结构的确定性。

relation()被正式命名为relationship()

这就解决了长期以来“关系”在关系代数术语中是指“表格或派生表格”的问题。relation()这个名字少了,所以在可预见的未来,这个变化应该是完全无痛的。

子查询渴望加载

一种新的急切的加载被称为“子查询”加载。这是一个负载,在第一个查询的第一个加载所有父项的完整集合之后立即发出第二个SQL查询,并使用INNER JOIN向上连接到父项。Subquery loading is used simlarly to the current joined-eager loading, using the `subqueryload()`` and ``subqueryload_all()`` options as well as the ``lazy='subquery'`` setting on ``relationship()`. 子查询加载通常会更加有效地加载许多较大的集合,因为它无条件地使用INNER JOIN,也不会重新加载父行。

`eagerload()``, ``eagerload_all()`` is now ``joinedload()``, ``joinedload_all()`

To make room for the new subquery load feature, the existing `eagerload()``/``eagerload_all()`` options are now superseded by ``joinedload()`` and ``joinedload_all()``. 旧的名字就像``relation()`一样,在可预见的将来会继续存在。

`lazy=False|None|True|'dynamic'`` now accepts ``lazy='noload'|'joined'|'subquery'|'select'|'dynamic'`

Continuing on the theme of loader strategies opened up, the standard keywords for the `lazy`` option on ``relationship()`` are now ``select`` for lazy loading (via a SELECT issued on attribute access), ``joined`` for joined-eager loading, ``subquery`` for subquery-eager loading, ``noload`` for no loading should occur, and ``dynamic`` for a “dynamic” relationship. 旧的``True````False````None`参数仍被接受,其行为与以前一样。

innerjoin =关于关系的True,joinedload

现在可以指示连接加载的标量和集合使用INNER JOIN而不是OUTER JOIN。在Postgresql上,观察到在某些查询中提供了300-600%的加速比。将此标志设置为任何多对一的不可空外键,对于其中保证相关项目存在的任何集合也是如此。

在mapper级别:

mapper(Child, child)
mapper(Parent, parent, properties={
    'child':relationship(Child, lazy='joined', innerjoin=True)
})

在查询时间级别:

session.query(Parent).options(joinedload(Parent.child, innerjoin=True)).all()

relationship()级别的innerjoin=True标志对任何不覆盖该值的joinedload()选项都会生效。

多对一的增强功能

  • 现在多对一的关系在更少的情况下触发延迟加载,在大多数情况下,当新的代码被替换时,不会获取“旧”的值。

  • 现在使用get()方法进行简单的加载(称为“use_get”条件),即Related - >“Sub(Base)而不需要根据基表重新定义主连接条件。[票:1186]

  • 指定具有声明列的外键,即ForeignKey(MyRelatedClass.id)不会破坏发生的“use_get”条件[ticket:1492]

  • relationship(),joinedload()和joinedload_all()现在具有一个名为“innerjoin”的选项。指定TrueFalse来控制eager连接是否构造为INNER或OUTER连接。默认是一如既往的False映射器选项将覆盖关系()中指定的任何设置。通常应该设置为多对一,而不是可空的外键关系,以提高连接性能。[票:1544]

  • 当LIMIT / OFFSET出现时,加入的预加载的行为使得主查询被包装在子查询中,现在对于所有紧急加载是多对一连接的情况都是例外的。在这种情况下,由于多对一连接不会将行添加到结果中,所以急切连接与限制/偏移量直接对抗父表,而没有额外的子查询开销。

    例如,在0.5这个查询中:

    session.query(Address).options(eagerload(Address.user)).limit(10)

    会产生像这样的SQL:

    SELECT * FROM
      (SELECT * FROM addresses LIMIT 10) AS anon_1
      LEFT OUTER JOIN users AS users_1 ON users_1.id = anon_1.addresses_user_id

    这是因为任何热心的加载器的存在表明它们中的一些或全部可能与多行集合有关,这将需要在子查询内包装任何类型的行计数敏感修饰符,如LIMIT。

    在0.6中,该逻辑更为敏感,并且可以检测所有渴望加载器是否表示多对一,在这种情况下,渴望加入不会影响行计数:

    SELECT * FROM addresses LEFT OUTER JOIN users AS users_1 ON users_1.id = addresses.user_id LIMIT 10

加入表继承的可变主键

一个连接表继承配置,其中子表具有一个PK,即父级PK的外键现在可以在支持CASCADE的数据库(如Postgresql)上更新。mapper()现在有一个选项passive_updates=True,表示这个外键是自动更新的。如果在像SQLite或MySQL / MyISAM这样的非级联数据库上,把这个标志设置为False未来的功能增强将尝试使此标志根据使用的方言/表格样式进行自动配置。

烧杯缓存

Beaker集成的一个有希望的新例子是在examples/beaker_caching中。这是一个直接的方法,它在Query的结果生成引擎中应用Beaker缓存。缓存参数通过query.options()提供,并允许完全控制缓存的内容。SQLAlchemy 0.6包含对Session.merge()方法的改进,以支持这个和类似的配方,并在大多数情况下提供显着改进的性能。

其他更改

  • 当多个列/实体被选择时,由Query返回的“行元组”对象现在可以被选择以及更高的执行。
  • query.join() has been reworked to provide more consistent behavior and more flexibility (includes [ticket:1537])
  • query.select_from() accepts multiple clauses to produce multiple comma separated entries within the FROM clause. 从多宿主连接()子句中选择时很有用。
  • the “dont_load=True” flag on Session.merge() is deprecated and is now “load=False”.
  • 添加了“make_transient()”辅助函数,该函数将持久性/分离性实例转换为临时性实例(即删除instance_key并从任何会话中删除)。[票:1052]
  • mapper()上的allow_null_pks标志已被弃用,并已被重命名为allow_partial_pks。它默认打开。这意味着对于任何主键列都有一个非空值的行将被认为是一个标识。通常只有在映射到外部联接时才需要这种情况。当设置为False时,其中包含NULL的PK不会被认为是主键 - 特别是,这意味着结果行将返回为None(或者不会被填充到集合中),0.6中的新值也表示会话.merge()不会针对这样一个PK值向数据库进行往返。[票:1680]
  • “backref”的机制已经完全合并到更细粒度的“back_populates”系统中,并且完全发生在RelationProperty_generate_backref()方法中。这使得RelationProperty的初始化过程更简单,并且允许设置(例如从RelationProperty的子类)更容易地传播到反向引用中。内部的BackRef()消失了,backref()返回一个被RelationProperty理解的普通元组。
  • the keys attribute of ResultProxy is now a method, so references to it (result.keys) must be changed to method invocations (result.keys())
  • ResultProxy.last_inserted_ids is now deprecated, use ResultProxy.inserted_primary_key instead.

已弃用/已删除ORM元素

绝大多数在整个0.5中弃用的元素和提出的弃用警告已被删除(有一些例外)。所有标记为“等待弃用”的元素现在都被弃用,并会在使用时引发警告。

  • sessionmaker()上的'transactional'标志被删除。使用'autocommit = True'来表示'transactional = False'。
  • mapper()上的'polymorphic_fetch'参数被删除。加载可以使用'with_polymorphic'选项进行控制。
  • mapper()上的“select_table”参数被删除。为此功能使用'with_polymorphic =(“*”,)“。
  • 同义词()的“代理”参数被删除。这个标志在整个0.5中没有做任何事情,因为“代理代”行为现在是自动的。
  • 将单个元素列表传递给joinedload(),joinedload_all(),contains_eager(),lazyload(),defer()和undefer()而不是多个位置* args已被弃用。
  • 将单个元素列表传递给query.order_by(),query.group_by(),query.join()或query.outerjoin()而不是多个位置*参数已被弃用。
  • query.iterate_instances() is removed. 使用query.instances()
  • Query.query_from_parent() is removed. Use the sqlalchemy.orm.with_parent() function to produce a “parent” clause, or alternatively query.with_parent().
  • query._from_self()被删除,改为使用query.from_self()
  • composite()的“comparator”参数被删除。使用“comparator_factory”。
  • RelationProperty._get_join() is removed.
  • Session上的'echo_uow'标志被删除。在“sqlalchemy.orm.unitofwork”名称上使用日志记录。
  • session.clear() is removed. 使用session.expunge_all()
  • session.save(), session.update(), session.save_or_update() are removed. 使用session.add()session.add_all()
  • session.flush()上的“objects”标志仍然被弃用。
  • session.merge()中的“dont_load = True”标志已弃用,以支持“load = False”。
  • ScopedSession.mapper remains deprecated. 请参阅http://www.sqlalchemy.org/trac/wiki/Usag eRecipes / SessionAwareMapper中的使用方法
  • InstanceState(内部SQLAlchemy状态对象)传递给attributes.init_collection()attributes.get_history()已弃用。这些函数是公共API,通常需要一个常规的映射对象实例。
  • declarative_base()的'engine'参数删除。使用“绑定”关键字参数。

扩展程序¶ T0>

SQLSoup ¶ T0>

SQLSoup已被升级和更新,以反映0.5 / 0.6的常见功能,包括定义良好的会话集成。请阅读[http://www.sqlalc hemy.org/docs/06/reference/ext/sqlsoup.html]上的新文档。

声明¶ T0>

之前,DeclarativeMetadeclarative_base的默认元类)允许子类修改dict_以添加类属性(例如列)。这不再有效,现在,DeclarativeMeta构造函数忽略了dict_相反,类属性应该直接分配,例如,应该使用cls.id=Column(...)MixIn类方法来代替元类方法。