Насколько мне известно, нет способа заставить ORM выполнять массовые вставки. Я считаю, что основная причина в том, что SQLAlchemy необходимо отслеживать идентичность каждого объекта (то есть новые первичные ключи), а массовая вставка мешает этому. Например, предположим, что ваша foo
таблица содержит id
столбец и сопоставлена с Foo
классом:
x = Foo(bar=1)
print x.id
# None
session.add(x)
session.flush()
# BEGIN
# INSERT INTO foo (bar) VALUES(1)
# COMMIT
print x.id
# 1
Поскольку SQLAlchemy получил значение для x.id
без выдачи другого запроса, мы можем сделать вывод, что он получил значение непосредственно из INSERT
оператора. Если вам не нужен последующий доступ к созданным объектам через те же экземпляры, вы можете пропустить слой ORM для своей вставки:
Foo.__table__.insert().execute([{'bar': 1}, {'bar': 2}, {'bar': 3}])
# INSERT INTO foo (bar) VALUES ((1,), (2,), (3,))
SQLAlchemy не может сопоставить эти новые строки с какими-либо существующими объектами, поэтому вам придется запрашивать их заново для любых последующих операций.
Что касается устаревших данных, полезно помнить, что сеанс не имеет встроенного способа узнать, когда база данных изменяется вне сеанса. Чтобы получить доступ к измененным извне данным через существующие экземпляры, экземпляры должны быть помечены как просроченные . По умолчанию это происходит session.commit()
, но это можно сделать вручную, позвонив session.expire_all()
или session.expire(instance)
. Пример (SQL опущен):
x = Foo(bar=1)
session.add(x)
session.commit()
print x.bar
# 1
foo.update().execute(bar=42)
print x.bar
# 1
session.expire(x)
print x.bar
# 42
session.commit()
истекает x
, поэтому первый оператор печати неявно открывает новую транзакцию и повторно запрашивает x
атрибуты. Если вы закомментируете первый оператор печати, вы заметите, что второй теперь принимает правильное значение, потому что новый запрос не создается до тех пор, пока не будет выполнено обновление.
Это имеет смысл с точки зрения изоляции транзакций - вы должны учитывать только внешние модификации между транзакциями. Если это вызывает у вас проблемы, я бы посоветовал уточнить или переосмыслить границы транзакций вашего приложения вместо того, чтобы немедленно достигать их session.expire_all()
.