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 users
sqlalchemy.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 users
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.
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 needed
DDL的“上下文”(如果有的话)将与上述标准替换结合使用。上下文中出现的键将覆盖标准替换。
__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
结构。