Как создать непостоянный объект Elixir/SQLAlchemy?
Из-за устаревших данных, которые недоступны в базе данных, но некоторые внешние файлы, я хочу создать объект SQLAlchemy, который содержит данные, считанные из внешних файлов, но не записывается в базу данных, если я выполняю session.flush()
Мой код выглядит так:
try:
return session.query(Phone).populate_existing().filter(Phone.mac == ident).one()
except:
return self.createMockPhoneFromLicenseFile(ident)
def createMockPhoneFromLicenseFile(self, ident):
# Some code to read necessary data from file deleted....
phone = Phone()
phone.mac = foo
phone.data = bar
phone.state = "Read from legacy file"
phone.purchaseOrderPosition = self.getLegacyOrder(ident)
# SQLAlchemy magic doesn't seem to work here, probably because we don't insert the created
# phone object into the database. So we set the id fields manually.
phone.order_id = phone.purchaseOrderPosition.order_id
phone.order_position_id = phone.purchaseOrderPosition.order_position_id
return phone
Все отлично работает, кроме того, что на session.flush()
Выполненный позже в приложении, SQLAlchemy пытается записать созданный объект Phone в базу данных (что, к счастью, не удается, потому что phone.state длиннее, чем позволяет тип данных), что нарушает функцию, которая выдает сброс.
Есть ли способ помешать SQLAlchemy написать такой объект?
Обновить
Пока я ничего не нашел на
using_mapper_options(save_on_init=False)
в документации по Elixir (может быть, вы можете предоставить ссылку?), мне показалось, что стоит попробовать (я бы предпочел способ предотвратить запись одного экземпляра вместо всей сущности).
Сначала казалось, что это утверждение не имеет никакого эффекта, и я подозревал, что мои версии SQLAlchemy/Elixir слишком старые, но потом я обнаружил, что соединение с сущностью PurchaseOrderPosition (которую я не изменял) было установлено с помощью
phone.purchaseOrderPosition = self.getLegacyOrder(ident)
заставляет телефонный объект быть записанным снова. Если я уберу заявление, все будет в порядке.
3 ответа
Вам нужно сделать
import elixir
elixir.options_defaults['mapper_options'] = { 'save_on_init': False }
предотвращать Entity
экземпляры, которые вы создаете, автоматически добавляются в сеанс. В идеале это должно быть сделано как можно раньше в вашем коде. Вы также можете сделать это для каждой отдельной сущности, через using_mapper_options(save_on_init=False)
- см. документацию Elixir для более подробной информации.
Обновить:
Смотрите этот пост в списке рассылки Elixir, указывая, что это решение.
Также, как отмечает Ants Aasma, вы можете использовать каскадные параметры в отношении Elixir для настройки каскадных параметров в SQLAlchemy. Смотрите эту страницу для более подробной информации.
Ну, sqlalchemy не, по умолчанию.
Рассмотрим следующий автономный пример кода.
from sqlalchemy import Column, Integer, Unicode, create_engine
from sqlalchemy.orm import create_session
from sqlalchemy.ext.declarative import declarative_base
e = create_engine('sqlite://')
Base = declarative_base(bind=e)
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(Unicode(50))
# create the empty table and a session
Base.metadata.create_all()
s = create_session(bind=e, autoflush=False, autocommit=False)
# assert the table is empty
assert s.query(User).all() == []
# create a new User instance but don't save it to database:
u = User()
u.name = 'siebert'
# I could run s.add(u) here but I won't
s.flush()
s.commit()
# assert the table is still empty
assert s.query(User).all() == []
Так что я не уверен, в чем бездействие, добавляя ваши экземпляры в сессию. Обычно вы должны вручную позвонить s.add(u)
чтобы он пошел на сессию. Я не знаком с эликсиром, так что, возможно, это какой-то трюк с эликсиром... Может быть, вы можете удалить его из сеанса, используя session.expunge()
,
Старый пост, но я столкнулся с подобной проблемой, в моем случае в sqlalchemy это было вызвано каскадом на backrefs:
http://docs.sqlalchemy.org/en/rel_0_7/orm/session.html
Отключите его на своих обратных ссылках, чтобы вам пришлось явно добавлять вещи в сеанс