MetaData / Schema

My program is hanging when I say table.drop() / metadata.drop_all()

This usually corresponds to two conditions: 1. using PostgreSQL, which is reallystrict about table locks, and 2. you have a connection still open whichcontains locks on the table and is distinct from the connection being used forthe DROP statement. Heres the most minimal version of the pattern:

  1. connection = engine.connect()
  2. result = connection.execute(mytable.select())
  3.  
  4. mytable.drop(engine)

Above, a connection pool connection is still checked out; furthermore, theresult object above also maintains a link to this connection. If“implicit execution” is used, the result will hold this connection opened untilthe result object is closed or all rows are exhausted.

The call to mytable.drop(engine) attempts to emit DROP TABLE on a secondconnection procured from the Engine which will lock.

The solution is to close out all connections before emitting DROP TABLE:

  1. connection = engine.connect()
  2. result = connection.execute(mytable.select())
  3.  
  4. # fully read result sets
  5. result.fetchall()
  6.  
  7. # close connections
  8. connection.close()
  9.  
  10. # now locks are removed
  11. mytable.drop(engine)

Does SQLAlchemy support ALTER TABLE, CREATE VIEW, CREATE TRIGGER, Schema Upgrade Functionality?

General ALTER support isn’t present in SQLAlchemy directly. For special DDLon an ad-hoc basis, the DDL and related constructs can be used.See core/ddl for a discussion on this subject.

A more comprehensive option is to use schema migration tools, such as Alembicor SQLAlchemy-Migrate; see Altering Schemas through Migrations for discussion on this.

How can I sort Table objects in order of their dependency?

This is available via the MetaData.sorted_tables function:

  1. metadata = MetaData()
  2. # ... add Table objects to metadata
  3. ti = metadata.sorted_tables:
  4. for t in ti:
  5. print(t)

How can I get the CREATE TABLE/ DROP TABLE output as a string?

Modern SQLAlchemy has clause constructs which represent DDL operations. Thesecan be rendered to strings like any other SQL expression:

  1. from sqlalchemy.schema import CreateTable
  2.  
  3. print(CreateTable(mytable))

To get the string specific to a certain engine:

  1. print(CreateTable(mytable).compile(engine))

There’s also a special form of Engine that can let you dump an entiremetadata creation sequence, using this recipe:

  1. def dump(sql, *multiparams, **params):
  2. print(sql.compile(dialect=engine.dialect))
  3. engine = create_engine('postgresql://', strategy='mock', executor=dump)
  4. metadata.create_all(engine, checkfirst=False)

The Alembic tool also supportsan “offline” SQL generation mode that renders database migrations as SQL scripts.

How can I subclass Table/Column to provide certain behaviors/configurations?

Table and Column are not good targets for direct subclassing.However, there are simple ways to get on-construction behaviors using creationfunctions, and behaviors related to the linkages between schema objects such asconstraint conventions or naming conventions using attachment events.An example of many of thesetechniques can be seen at Naming Conventions.