Метаданные / Схема

Моя программа зависает, когда я говорю table.drop() / metadata.drop_all()

Обычно это соответствует двум условиям: 1. вы используете PostgreSQL, который очень строго относится к блокировкам таблиц, и 2. у вас еще открыто соединение, содержащее блокировки на таблицу и отличное от соединения, используемого для оператора DROP. Вот самый минимальный вариант паттерна:

connection = engine.connect()
result = connection.execute(mytable.select())

mytable.drop(engine)

Выше соединение пула соединений все еще проверяется; кроме того, в объекте result также сохраняется ссылка на это соединение. Если используется «неявное выполнение», то результат будет держать это соединение открытым до тех пор, пока объект result не будет закрыт или не будут исчерпаны все строки.

Вызов mytable.drop(engine) пытается выдать DROP TABLE на втором соединении, полученном от Engine, которое блокируется.

Решением является закрытие всех соединений перед выдачей DROP TABLE:

connection = engine.connect()
result = connection.execute(mytable.select())

# fully read result sets
result.fetchall()

# close connections
connection.close()

# now locks are removed
mytable.drop(engine)

Поддерживает ли SQLAlchemy функциональность ALTER TABLE, CREATE VIEW, CREATE TRIGGER, Schema Upgrade?

Общая поддержка ALTER непосредственно в SQLAlchemy отсутствует. Для специальных DDL на разовой основе можно использовать DDL и связанные с ним конструкции. Обсуждение этого вопроса см. в разделе Настройка DDL.

Более полным вариантом является использование средств миграции схем, таких как Alembic или SQLAlchemy-Migrate; обсуждение этого вопроса см. в Изменение объектов базы данных с помощью миграции.

Как отсортировать объекты таблицы в порядке их зависимости?

Это доступно через функцию MetaData.sorted_tables:

metadata_obj = MetaData()
# ... add Table objects to metadata
ti = metadata_obj.sorted_tables
for t in ti:
    print(t)

Как получить вывод CREATE TABLE/ DROP TABLE в виде строки?

В современной SQLAlchemy есть конструкции clause, которые представляют операции DDL. Они могут быть приведены к строкам, как и любые другие выражения SQL:

from sqlalchemy.schema import CreateTable

print(CreateTable(mytable))

Для получения строки, характерной для конкретного двигателя:

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

Существует также специальная форма Engine, доступная через create_mock_engine(), которая позволяет выгрузить всю последовательность создания метаданных в виде строки по следующему рецепту:

from sqlalchemy import create_mock_engine


def dump(sql, *multiparams, **params):
    print(sql.compile(dialect=engine.dialect))


engine = create_mock_engine("postgresql+psycopg2://", dump)
metadata_obj.create_all(engine, checkfirst=False)

Инструмент Alembic также поддерживает режим «автономной» генерации SQL, в котором миграции баз данных выполняются в виде SQL-скриптов.

Как я могу подклассифицировать Table/Column для обеспечения определенного поведения/конфигурации?

Table и Column не являются хорошими объектами для прямого подклассифицирования. Однако есть простые способы получить поведение при построении с помощью функций создания, а также поведение, связанное со связями между объектами схемы, такими как соглашения об ограничениях или соглашения об именовании, с помощью событий вложения. Пример многих из этих приемов можно увидеть в Naming Conventions.

Вернуться на верх