Насколько я знаю, нет способа заставить 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 не может соответствовать этим новым строкамс любыми существующими объектами, поэтому вам придется заново запрашивать их для любых последующих операций.
Что касается устаревших данных, полезно помнить, что в сеансе нет встроенного способа узнать, когдабаза данных изменена вне сеанса.Чтобы получить доступ к измененным извне данным через существующие экземпляры, они должны быть помечены как expired .Это происходит по умолчанию на 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()
expires x
, поэтому первый оператор print неявно открывает новую транзакцию и повторно запрашивает атрибуты x
.Если вы закомментируете первый оператор печати, вы заметите, что второй теперь выбирает правильное значение, потому что новый запрос не генерируется до окончания обновления.
Это имеет смысл с точки зренияпредставление о транзакционной изоляции - вы должны выбирать только внешние модификации между транзакциями.Если это вызывает у вас проблемы, я бы предложил уточнить или переосмыслить границы транзакций вашего приложения вместо того, чтобы сразу же достигать session.expire_all()
.