2017-01-26 2 views
0

Есть ли способ явно помечать объект как clean в ORM SQLAlchemy?Маркировка объекта как чистого в SQLAlchemy ORM

Отчасти это связано с предыдущим вопросом на bulk update strategies.

Я хочу, чтобы в течение before_flush прослушиватель событий отмечал кучу объекта, поскольку на самом деле его не нужно было смывать. Это связано с тем, что они вручную синхронизируются с базой данных другими способами.

Я пробовал стратегию ниже, но это приводит к удалению объекта из сеанса, что впоследствии может вызвать проблемы позже, когда происходит ленивая загрузка.

@event.listens_for(SignallingSession, 'before_flush') 
def before_flush(session, flush_context, instances): 
    ledgers = [] 

    if session.dirty: 
     for elem in session.dirty: 
      if (session.is_modified(elem, include_collections=False)): 
       if isinstance(elem, Wallet): 
        session.expunge(elem) # causes problems later 
        ledgers.append(Ledger(id=elem.id, amount=elem.balance)) 

    if ledgers: 
     session.bulk_save_objects(ledgers) 
     session.execute('UPDATE wallet w JOIN ledger l on w.id = l.id SET w.balance = l.amount') 
     session.execute('TRUNCATE ledger') 

Я хочу сделать что-то вроде:

session.dirty.remove(MyObject) 

Но это не работает, как session.dirty является вычисляемым свойство, а не обычный атрибут. Я копал код инструментария, но не вижу, как я могу обмануть список dirty, чтобы он не содержал что-то. Я вижу, есть также history о состоянии объекта, о котором нужно будет заботиться также.

Любые идеи? Базовая база данных - это MySQL, если это имеет значение.

Матф

ответ

1

При изменении базы данных за пределами ОРМ, вы можете позволить ORM знать текущее состояние базы данных с помощью set_committed_value().

Пример:

wallet = session.query(Wallet).filter_by(id=123) 
wallet.balance = 0 
session.execute("UPDATE wallet SET balance = 0 WHERE id = 123;") 
set_committed_value(wallet, "balance", 0) 
session.commit() # won't issue additional SQL to update wallet 

Если вы действительно хотел, чтобы отметить экземпляр, как не загрязнен, вы можете сбросить с внутренностями SQLAlchemy:

state = inspect(p) 
session.identity_map._modified.discard(state) 
state.modified = False 
print(p in session.dirty) # False 
+0

Увы, не совсем то, что делать Я хочу, чтобы это делалось, как будто 'кошелек' уже находится в' session.dirty' в силу того, что, если ему присвоено новое значение, я хочу * удалить * его из грязного списка. Если я использую 'set_committed_value()', то он изменяет значение, но объект остается в грязном списке. –

+1

@MattHamilton Он остается в грязном списке, но 'is_modified' вернет' False'. – univerio

+0

Ahhh правильно, спасибо! Поэтому, пока он кажется грязным, флеш на самом деле не имеет работы. Немного больше, чтобы перекопать этот метод, и то, что у меня получилось, это: 'instance_state (obj) .committed_state.clear()', чтобы очистить состояние объекта –

Смежные вопросы