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

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

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

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

mytable.drop(engine)

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

Вызов 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, обновление схемы?

Общая поддержка 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://", dump)
metadata_obj.create_all(engine, checkfirst=False)

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

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

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

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