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元素一样工作,除了它接受一个字符串,它是要发射的文本:
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构造也具有基于对数据库的检查有条件调用的能力。该功能可以使用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)
CREATE TABLE users (
user_id SERIAL NOT NULL,
user_name VARCHAR(40) NOT NULL,
PRIMARY KEY (user_id)
)
select conname from pg_constraint where conname='cst_user_name_length'
ALTER TABLE users ADD CONSTRAINT cst_user_name_length CHECK (length(user_name) >= 8)
sqlusers.drop(engine)
select conname from pg_constraint where conname='cst_user_name_length'
ALTER TABLE users DROP CONSTRAINT cst_user_name_length
DROP TABLE userssqlalchemy.schema包包含提供DDL表达式的SQL表达式结构。例如,要产生一个CREATE TABLE语句:
from sqlalchemy.schema import CreateTable
sqlengine.execute(CreateTable(mytable))
CREATE TABLE mytable (
col1 INTEGER,
col2 INTEGER,
col3 INTEGER,
col4 INTEGER,
col5 INTEGER,
col6 INTEGER
)在上面,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事件系统将考虑目前在所有情况下调用的内置构造。
我们可以用AddConstraint和DropConstraint结构来说明一个事件驱动的例子,因为事件驱动系统可以用于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)
CREATE TABLE users (
user_id SERIAL NOT NULL,
user_name VARCHAR(40) NOT NULL,
PRIMARY KEY (user_id)
)
select conname from pg_constraint where conname='cst_user_name_length'
ALTER TABLE users ADD CONSTRAINT cst_user_name_length CHECK (length(user_name) >= 8)
sqlusers.drop(engine)
select conname from pg_constraint where conname='cst_user_name_length'
ALTER TABLE users DROP CONSTRAINT cst_user_name_length
DROP TABLE usersWhile 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.
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()函数来打破涉及分开循环。
| 参数: |
|
|---|
sqlalchemy.schema.sort_tables_and_constraints(tables, filter_fn=None, extra_dependencies=None)¶对Table / ForeignKeyConstraint对象的集合进行排序。
这是一个依赖排序的排序,它将发出(Table, [ForeignKeyConstraint, ...]) t0的元组>使得每个Remaining Table遵循其依赖的Table对象。ForeignKeyConstraint objects that are separate due to dependency rules not satisifed by the sort are emitted afterwards as (None, [ForeignKeyConstraint ...]).
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.
| 参数: |
|
|---|
版本1.0.0中的新功能
也可以看看
sqlalchemy.schema。 DDLElement ¶基础:sqlalchemy.sql.expression.Executable,sqlalchemy.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与Events中介绍的SQLAlchemy事件紧密集成。一个实例本身就是一个接收可调用的事件:
event.listen(
users,
'after_create',
AddConstraint(constraint).execute_if(dialect='postgresql')
)__ call __ ( target,bind,** kw T5> ¶ T6>以ddl_listener的身份执行DDL。
针对 T0> ( T1> 靶 T2> ) T3> ¶ T4>针对特定模式项目返回此DDL的副本。
结合 T0> ¶ T1>callable _ =无 ¶方言 =无 ¶execute(bind=None, target=None)¶立即执行此DDL。
如果未提供,则使用分配给.bind属性的Connectable或Connectable执行DDL语句。如果DDL在标准上有条件的on
| 参数: |
|
|---|
execute_at(event_name, target)¶将此DDL的执行链接到SchemaItem的DDL生命周期。
从版本0.7开始弃用:请参阅DDLEvents以及DDLElement.execute_if()。
将此DDLElement链接到Table或MetaData实例,并在该架构项创建或删除时执行该实例。DDL语句将使用与表创建/删除本身相同的连接和事务上下文来执行。该语句的.bind属性被忽略。
| 参数: |
|---|
DDLElement实例可以链接到任意数量的模式项目。
execute_at建立在MetaData和Table对象的append_ddl_listener接口上。
警告:创建或删除独立的表也会触发任何DDL设置为execute_at表的元数据。这可能会在未来的版本中发生变化。
execute_if ( dialect = None,callable_ = None,state = None ) T5> ¶ T6>返回可执行此DDLElement的可调用对象。
用于提供事件监听的包装:
event.listen(
metadata,
'before_create',
DDL("my_ddl").execute_if(dialect='postgresql')
)| 参数: |
|
|---|
on =无 ¶目标 =无 ¶sqlalchemy.schema。 DDL ( 语句,on =无context = None,bind = None ) ¶基础:sqlalchemy.schema.DDLElement
一个文字DDL语句。
指定要由数据库执行的文字SQL DDL。DDL对象充当DDL事件侦听器,可以使用Table或MetaData对象作为目标来订阅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 neededDDL的“上下文”(如果有的话)将与上述标准替换结合使用。上下文中出现的键将覆盖标准替换。
__init__(statement, on=None, context=None, bind=None)¶创建一个DDL语句。
| 参数: |
|
|---|
sqlalchemy.schema._CreateDropBase(element, on=None, bind=None)¶基础:sqlalchemy.schema.DDLElement
表示CREATE和DROP或等价物的DDL结构的基类。
_CreateDropBase的常见主题是单个element属性,它指向要创建或删除的元素。
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结构。
| 参数: |
|---|
sqlalchemy.schema.DropTable(element, on=None, bind=None)¶基础:sqlalchemy.schema._CreateDropBase
表示DROP TABLE语句。
sqlalchemy.schema。 CreateColumn ( 元素 ) t5 > ¶ T6>基础:sqlalchemy.schema._DDLCompiles
将Column表示为通过CreateTable结构呈现在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参数相同的效果,它将列标记为隐式存在的“系统”列。
例如,假设我们希望产生一个Table,该表跳过Postgresql后端对Postgresql xmin列的渲染,但是在其他后端确实呈现它,预期触发规则。条件编译规则可以仅在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结构以支持自定义列创建样式。
sqlalchemy.schema.CreateSequence(element, on=None, bind=None)¶基础:sqlalchemy.schema._CreateDropBase
表示一个CREATE SEQUENCE语句。
sqlalchemy.schema.DropSequence(element, on=None, bind=None)¶基础:sqlalchemy.schema._CreateDropBase
表示DROP SEQUENCE语句。
sqlalchemy.schema.CreateIndex(element, on=None, bind=None)¶基础:sqlalchemy.schema._CreateDropBase
表示CREATE INDEX语句。
sqlalchemy.schema.DropIndex(element, on=None, bind=None)¶基础:sqlalchemy.schema._CreateDropBase
代表DROP INDEX语句。
sqlalchemy.schema。 AddConstraint ( 元素,/ t5>,** kw ) ¶基础:sqlalchemy.schema._CreateDropBase
表示ALTER TABLE ADD CONSTRAINT语句。
sqlalchemy.schema。 DropConstraint ( 元素,cascade = False ,** kw ) ¶基础:sqlalchemy.schema._CreateDropBase
表示一个ALTER TABLE DROP CONSTRAINT语句。
sqlalchemy.schema。 CreateSchema ( name,quote =无,** kw ) ¶基础:sqlalchemy.schema._CreateDropBase
表示CREATE SCHEMA语句。
New in version 0.7.4.
这里的参数是模式的字符串名称。
__ init __ ( name,quote =无,** kw ) T5> ¶ T6>创建一个新的CreateSchema结构。
sqlalchemy.schema。 DropSchema ( name,quote =无cascade = False,** kw ) ¶基础:sqlalchemy.schema._CreateDropBase
代表DROP SCHEMA语句。
这里的参数是模式的字符串名称。
New in version 0.7.4.
__init__(name, quote=None, cascade=False, **kw)¶创建一个新的DropSchema结构。