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

SQLAlchemy 1.1文档

定制DDL

In the preceding sections we’ve discussed a variety of schema constructs including Table, ForeignKeyConstraint, CheckConstraint, and Sequence. Throughout, we’ve relied upon the create() and create_all() methods of Table and MetaData in order to issue data definition language (DDL) for all constructs. 在发布时,调用预定义的操作顺序,并且创建每个表的DDL被无条件地创建,包括与其相关联的所有约束和其他对象。对于需要特定于数据库的DDL的更复杂场景,SQLAlchemy提供了两种技术,可以根据任何条件添加任何DDL,可以伴随标准的表生成或自身。

自定义DDL

自定义的DDL短语最容易使用DDL构造来实现。这个构造像所有其他的DDL元素一样工作,除了它接受一个字符串,它是要发射的文本:

event.listen(
    metadata,
    "after_create",
    DDL("ALTER TABLE users ADD CONSTRAINT "
        "cst_user_name_length "
        " CHECK (length(user_name) >= 8)")
)

创建DDL结构库的更全面的方法是使用自定义编译 - 有关详细信息,请参阅Custom SQL Constructs and Compilation Extension

控制DDL序列

以前引入的DDL构造也具有根据对数据库的检查有条件调用的能力。该功能可以使用DDLElement.execute_if()方法。例如,如果我们想创建一个触发器,但只在Postgresql后端,我们可以这样调用:

mytable = Table(
    'mytable', metadata,
    Column('id', Integer, primary_key=True),
    Column('data', String(50))
)

trigger = DDL(
    "CREATE TRIGGER dt_ins BEFORE INSERT ON mytable "
    "FOR EACH ROW BEGIN SET NEW.data='ins'; END"
)

event.listen(
    mytable,
    'after_create',
    trigger.execute_if(dialect='postgresql')
)

DDLElement.execute_if.dialect关键字也接受字符串方言名称的元组:

event.listen(
    mytable,
    "after_create",
    trigger.execute_if(dialect=('postgresql', 'mysql'))
)
event.listen(
    mytable,
    "before_drop",
    trigger.execute_if(dialect=('postgresql', 'mysql'))
)

DDLElement.execute_if()方法也可以针对将要接收正在使用的数据库连接的可调用函数。在下面的例子中,我们使用这个来有条件地创建一个CHECK约束,首先在Postgresql目录中查看它是否存在:

def should_create(ddl, target, connection, **kw):
    row = connection.execute(
        "select conname from pg_constraint where conname='%s'" %
        ddl.element.name).scalar()
    return not bool(row)

def should_drop(ddl, target, connection, **kw):
    return not should_create(ddl, target, connection, **kw)

event.listen(
    users,
    "after_create",
    DDL(
        "ALTER TABLE users ADD CONSTRAINT "
        "cst_user_name_length CHECK (length(user_name) >= 8)"
    ).execute_if(callable_=should_create)
)
event.listen(
    users,
    "before_drop",
    DDL(
        "ALTER TABLE users DROP CONSTRAINT cst_user_name_length"
    ).execute_if(callable_=should_drop)
)

sqlusers.create(engine)

sqlusers.drop(engine)

使用内置的DDLElement类

The sqlalchemy.schema package contains SQL expression constructs that provide DDL expressions. 例如,要产生一个CREATE TABLE语句:

from sqlalchemy.schema import CreateTable
sqlengine.execute(CreateTable(mytable))

在上面,CreateTable构造像任何其他表达式构造(如select()table.insert())一样工作。所有SQLAlchemy的面向DDL的结构都是DDLElement基类的子类;这是对应于CREATE和DROP以及ALTER的所有对象的基础,不仅在SQLAlchemy中,而且在Alembic Migrations中也是如此。可用构造的完整参考在DDL Expression Constructs API中。

用户定义的DDL结构也可以创建为DDLElement本身的子类。Custom SQL Constructs and Compilation Extension中的文档有几个例子。

上一节Controlling DDL Sequences中描述的事件驱动的DDL系统也可以与其他DDLElement对象一起使用。However, when dealing with the built-in constructs such as CreateIndex, CreateSequence, etc, the event system is of limited use, as methods like Table.create() and MetaData.create_all() will invoke these constructs unconditionally. 在未来的SQLAlchemy发行版中,包含条件执行的DDL事件系统将考虑目前在所有情况下调用的内置构造。

我们可以用AddConstraintDropConstraint结构来说明一个事件驱动的例子,因为事件驱动的系统可以用于CHECK和UNIQUE约束,就像我们在前面的DDLElement.execute_if()的例子:

def should_create(ddl, target, connection, **kw):
    row = connection.execute(
        "select conname from pg_constraint where conname='%s'" %
        ddl.element.name).scalar()
    return not bool(row)

def should_drop(ddl, target, connection, **kw):
    return not should_create(ddl, target, connection, **kw)

event.listen(
    users,
    "after_create",
    AddConstraint(constraint).execute_if(callable_=should_create)
)
event.listen(
    users,
    "before_drop",
    DropConstraint(constraint).execute_if(callable_=should_drop)
)

sqlusers.create(engine)

sqlusers.drop(engine)

While the above example is against the built-in AddConstraint and DropConstraint objects, the main usefulness of DDL events for now remains focused on the use of the DDL construct itself, as well as with user-defined subclasses of DDLElement that aren’t already part of the MetaData.create_all(), Table.create(), and corresponding “drop” processes.

DDL表达式构造API

sqlalchemy.schema.sort_tables(tables, skip_fn=None, extra_dependencies=None)

根据依赖关系排序Table对象的集合。

这是一个依赖排序的排序,它将发射Table对象,以便它们将遵循相关的Table对象。表依赖于另一个表,这些表是基于ForeignKeyConstraint对象的存在以及由Table.add_is_dependent_on()添加的显式依赖关系。

警告

The sort_tables() function cannot by itself accommodate automatic resolution of dependency cycles between tables, which are usually caused by mutually dependent foreign key constraints. 要解决这些循环,可以将ForeignKeyConstraint.use_alter参数应用于这些约束,或者使用sql.sort_tables_and_constraints()函数来打破涉及的外键约束单独循环。

参数:
  • tables – a sequence of Table objects.
  • skip_fn – optional callable which will be passed a ForeignKey object; if it returns True, this constraint will not be considered as a dependency. Note this is different from the same parameter in sort_tables_and_constraints(), which is instead passed the owning ForeignKeyConstraint object.
  • extra_dependencies – a sequence of 2-tuples of tables which will also be considered as dependent on each other.

也可以看看

sort_tables_and_constraints()

MetaData.sorted_tables() - uses this function to sort

sqlalchemy.schema.sort_tables_and_constraints(tables, filter_fn=None, extra_dependencies=None)

Table / ForeignKeyConstraint对象的集合进行排序。

这是一个依赖排序的排序,它将发射(Table, [ForeignKeyConstraint, ...])的元组 >使得每个Table遵循其依赖的Table对象。剩余的ForeignKeyConstraint对象由于依赖性规则而不相关,因此不会被排序所满足,这些对象之后被发送为(None, [ForeignKeyConstraint ...]) T6> T3>。

Tables are dependent on another based on the presence of ForeignKeyConstraint objects, explicit dependencies added by Table.add_is_dependent_on(), as well as dependencies stated here using the skip_fn and/or extra_dependencies parameters.

参数:
  • tables – a sequence of Table objects.
  • filter_fn – optional callable which will be passed a ForeignKeyConstraint object, and returns a value based on whether this constraint should definitely be included or excluded as an inline constraint, or neither. 如果返回False,那么这个约束肯定会作为一个依赖项被包含在ALTER中;如果为True,则仅在结尾处包含作为ALTER结果。返回无意味着约束被包含在基于表格的结果中,除非它被检测为依赖周期的一部分。
  • extra_dependencies – a sequence of 2-tuples of tables which will also be considered as dependent on each other.

版本1.0.0中的新功能

也可以看看

sort_tables()

class sqlalchemy.schema。 DDLElement

基础:sqlalchemy.sql.expression.Executablesqlalchemy.schema._DDLCompiles

DDL表达式构造的基类。

This class is the base for the general purpose DDL class, as well as the various create/drop clause constructs such as CreateTable, DropTable, AddConstraint, etc.

DDLElement integrates closely with SQLAlchemy events, introduced in Events. 一个实例本身就是一个接收可调用的事件:

event.listen(
    users,
    'after_create',
    AddConstraint(constraint).execute_if(dialect='postgresql')
)
__call__(target, bind, **kw)

作为ddl_listener执行DDL。

针对 T0> ( T1> 靶 T2> ) T3> ¶ T4>

根据特定模式项目返回此DDL的副本。

结合 T0> ¶ T1>
callable _ =无
方言 =无
execute(bind=None, target=None)

立即执行此DDL。

如果未提供,则使用分配给.bind属性的ConnectableConnectable执行DDL语句。如果DDL在标准上有一个条件on

参数:
  • bind – Optional, an Engine or Connection. 如果未提供,则.bind属性中必须存在有效​​的Connectable
  • target - 可选,默认为None。执行调用的目标SchemaItem。将被传递给on callable(如果有),并且还可以为该语句提供字符串扩展数据。有关更多信息,请参见execute_at
execute_at(event_name, target)

将此DDL的执行链接到SchemaItem的DDL生命周期。

从版本0.7开始弃用:请参阅DDLEvents以及DDLElement.execute_if()

将这个DDLElement链接到TableMetaData实例,在创建或删除模式项时执行它。DDL语句将使用与表创建/删除本身相同的连接和事务上下文来执行。这个语句的.bind属性被忽略。

参数:
  • event – One of the events defined in the schema item’s .ddl_events; e.g. ‘before-create’, ‘after-create’, ‘before-drop’ or ‘after-drop’
  • target – The Table or MetaData instance for which this DDLElement will be associated with.

DDLElement实例可以链接到任意数量的模式项目。

execute_at建立在MetaDataTable对象的append_ddl_listener接口上。

警告:创建或删除一个孤立的表也会触发任何DDL设置为execute_at该表的元数据。这可能会在未来的版本中发生变化。

execute_if dialect = Nonecallable_ = Nonestate = None ) T5> ¶ T6>

返回可执行此DDLElement的可调用对象。

用于提供事件监听的包装:

event.listen(
            metadata,
            'before_create',
            DDL("my_ddl").execute_if(dialect='postgresql')
        )
参数:
  • dialect -

    可能是一个字符串,元组或可调用的谓词。如果一个字符串,它将被比较为正在执行的数据库方言的名字:

    DDL('something').execute_if(dialect='postgresql')

    如果一个元组指定多个方言名称:

    DDL('something').execute_if(dialect=('postgresql', 'mysql'))
  • callable _ -

    一个可调用的,将被调用四个位置参数以及可选的关键字参数:

    DDL:这个DDL元素。
    目标:该事件的目标TableMetaData对象。如果DDL是明确执行的,可能是None。
    绑定:用于DDL执行的Connection
    表:可选关键字参数 - 在MetaData.create_all()或drop_all()方法调用中创建/删除的表对象列表。
    州:可选的关键字参数 - 将是传递给此函数的state参数。
    checkfirst:Keyword argument, will be True if the ‘checkfirst’ flag was set during the call to create(), create_all(), drop(), drop_all().

    如果可调用函数返回一个真值,则会执行DDL语句。

  • state – any value which will be passed to the callable_ as the state keyword argument.

也可以看看

DDLEvents

Events

on =无
目标 =无
class sqlalchemy.schema.DDL(statement, on=None, context=None, bind=None)

基础:sqlalchemy.schema.DDLElement

一个直接的DDL语句。

指定要由数据库执行的文字SQL DDL。DDL对象作为DDL事件侦听器,可以使用TableMetaData对象作为目标,订阅DDLEvents中列出的事件。基本模板支持允许单个DDL实例处理多个表的重复任务。

例子:

from sqlalchemy import event, DDL

tbl = Table('users', metadata, Column('uid', Integer))
event.listen(tbl, 'before_create', DDL('DROP TRIGGER users_trigger'))

spow = DDL('ALTER TABLE %(table)s SET secretpowers TRUE')
event.listen(tbl, 'after_create', spow.execute_if(dialect='somedb'))

drop_spow = DDL('ALTER TABLE users SET secretpowers FALSE')
connection.execute(drop_spow)

在Table事件上运行时,可以使用下面的statement字符串替换:

%(table)s  - the Table name, with any required quoting applied
%(schema)s - the schema name, with any required quoting applied
%(fullname)s - the Table name including schema, quoted if needed

DDL的“背景”(如果有的话)将与上述的标准替换相结合。上下文中的键将覆盖标准替换。

__init__(statement, on=None, context=None, bind=None)

创建一个DDL语句。

参数:
  • 语句 -

    要执行的字符串或unicode字符串。语句将使用Python的字符串格式化操作符处理。请参阅context参数和execute_at方法。

    语句中的文字'%'必须转义为'%%'。

    SQL绑定参数在DDL语句中不可用。

  • on -

    从版本0.7开始弃用:请参阅DDLElement.execute_if()

    可选的过滤标准。可能是一个字符串,元组或可调用的谓词。如果一个字符串,它将被比较为正在执行的数据库方言的名字:

    DDL('something', on='postgresql')

    如果一个元组指定多个方言名称:

    DDL('something', on=('postgresql', 'mysql'))

    如果是可调用的,则会调用四个位置参数以及可选的关键字参数:

    DDL:这个DDL元素。
    事件:触发此DDL的事件的名称(如“after-create”)如果显式执行DDL,则为None。
    目标:该事件的目标是TableMetaData对象。如果DDL是明确执行的,可能是None。
    连接:用于DDL执行的Connection
    表:可选关键字参数 - 在MetaData.create_all()或drop_all()方法调用中创建/删除的表对象列表。

    如果可调用函数返回一个真值,则会执行DDL语句。

  • context – Optional dictionary, defaults to None. 这些值将可用于DDL语句中的字符串替换。
  • 绑定 - 可选。Connectable,当execute()没有绑定参数时被调用。

也可以看看

DDLEvents

Events

class sqlalchemy.schema._CreateDropBase(element, on=None, bind=None)

基础:sqlalchemy.schema.DDLElement

表示CREATE和DROP或等价的DDL结构的基类。

_CreateDropBase的常见主题是单个element属性,它指向要创建或删除的元素。

class sqlalchemy.schema.CreateTable(element, on=None, bind=None, include_foreign_key_constraints=None)

基础:sqlalchemy.schema._CreateDropBase

表示一个CREATE TABLE语句。

__init__(element, on=None, bind=None, include_foreign_key_constraints=None)

创建一个CreateTable结构。

参数:
  • element – a Table that’s the subject of the CREATE
  • on – See the description for ‘on’ in DDL.
  • bind – See the description for ‘bind’ in DDL.
  • include_foreign_key_constraints -

    将被包含在CREATE结构内的ForeignKeyConstraint对象的可选序列;如果省略,则包含所有不指定use_alter = True的外键约束。

    版本1.0.0中的新功能

class sqlalchemy.schema。 DropTable 元素,on =无bind = None

基础:sqlalchemy.schema._CreateDropBase

表示一个DROP TABLE语句。

class sqlalchemy.schema。 CreateColumn 元素 ) t5 > ¶ T6>

基础:sqlalchemy.schema._DDLCompiles

通过CreateTable构造将一个Column表示为在CREATE TABLE语句中呈现。

通过使用Custom SQL Constructs and Compilation Extension中介绍的编译器扩展来扩展CreateColumn,可以在CREATE TABLE语句的生成中支持自定义列DDL。

典型的集成是检查传入的Column对象,并在找到特定标志或条件时重定向编译:

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

@compiles(schema.CreateColumn)
def compile(element, compiler, **kw):
    column = element.element

    if "special" not in column.info:
        return compiler.visit_create_column(element, **kw)

    text = "%s SPECIAL DIRECTIVE %s" % (
            column.name,
            compiler.type_compiler.process(column.type)
        )
    default = compiler.get_column_default_string(column)
    if default is not None:
        text += " DEFAULT " + default

    if not column.nullable:
        text += " NOT NULL"

    if column.constraints:
        text += " ".join(
                    compiler.process(const)
                    for const in column.constraints)
    return text

上面的结构可以应用于Table,如下所示:

from sqlalchemy import Table, Metadata, Column, Integer, String
from sqlalchemy import schema

metadata = MetaData()

table = Table('mytable', MetaData(),
        Column('x', Integer, info={"special":True}, primary_key=True),
        Column('y', String(50)),
        Column('z', String(20), info={"special":True})
    )

metadata.create_all(conn)

以上,我们添加到Column.info集合的指令将被我们的自定义编译方案检测到:

CREATE TABLE mytable (
        x SPECIAL DIRECTIVE INTEGER NOT NULL,
        y VARCHAR(50),
        z SPECIAL DIRECTIVE VARCHAR(20),
    PRIMARY KEY (x)
)

当生成CREATE TABLE时,也可​​以使用CreateColumn构造跳过某些列。这是通过创建一个有条件返回None的编译规则来完成的。这本质上是如何产生与在Column上使用system=True参数相同的效果,它将列标记为隐式存在的“系统”列。

For example, suppose we wish to produce a Table which skips rendering of the Postgresql xmin column against the Postgresql backend, but on other backends does render it, in anticipation of a triggered rule. 条件编译规则只能在Postgresql上跳过这个名字:

from sqlalchemy.schema import CreateColumn

@compiles(CreateColumn, "postgresql")
def skip_xmin(element, compiler, **kw):
    if element.element.name == 'xmin':
        return None
    else:
        return compiler.visit_create_column(element, **kw)


my_table = Table('mytable', metadata,
            Column('id', Integer, primary_key=True),
            Column('xmin', Integer)
        )

上面,一个CreateTable结构将产生一个CREATE TABLE,它只包含id字符串中的列; xmin列将被省略,但仅针对Postgresql后端。

0.8.3版新增: CreateColumn结构支持通过从自定义编译规则返回None跳过列。

0.8版新增:添加了CreateColumn结构以支持自定义列创建样式。

class sqlalchemy.schema.CreateSequence(element, on=None, bind=None)

基础:sqlalchemy.schema._CreateDropBase

表示一个CREATE SEQUENCE语句。

class sqlalchemy.schema.DropSequence(element, on=None, bind=None)

基础:sqlalchemy.schema._CreateDropBase

表示一个DROP SEQUENCE语句。

class sqlalchemy.schema.CreateIndex(element, on=None, bind=None)

基础:sqlalchemy.schema._CreateDropBase

表示一个CREATE INDEX语句。

class sqlalchemy.schema.DropIndex(element, on=None, bind=None)

基础:sqlalchemy.schema._CreateDropBase

代表DROP INDEX语句。

class sqlalchemy.schema.AddConstraint(element, *args, **kw)

基础:sqlalchemy.schema._CreateDropBase

表示一个ALTER TABLE ADD CONSTRAINT语句。

class sqlalchemy.schema.DropConstraint(element, cascade=False, **kw)

基础:sqlalchemy.schema._CreateDropBase

表示一个ALTER TABLE DROP CONSTRAINT语句。

class sqlalchemy.schema.CreateSchema(name, quote=None, **kw)

基础:sqlalchemy.schema._CreateDropBase

表示一个CREATE SCHEMA语句。

0.7.4版本的新功能

这里的参数是模式的字符串名称。

__init__(name, quote=None, **kw)

创建一个新的CreateSchema结构。

class sqlalchemy.schema.DropSchema(name, quote=None, cascade=False, **kw)

基础:sqlalchemy.schema._CreateDropBase

代表DROP SCHEMA语句。

这里的参数是模式的字符串名称。

0.7.4版本的新功能

__init__(name, quote=None, cascade=False, **kw)

创建一个新的DropSchema结构。