2013-03-13 26 views
10

Chcę odłączyć instancję klasy od mojej sesji, ale powinna ona nadal być dostępna do odczytu (bez wysyłania zapytania). I zostały przez skanowanie dokumentacji dni teraz, ale każde podejście staram prowadzi do wiadomościOdłączanie instancji SQLAlchemy, aby nie było odświeżania.

DetachedInstanceError: Instance <MyModel at 0x36bb190> is not bound to a Session; 
attribute refresh operation cannot proceed 

pracuję z menedżerem zope.sqlalchemy transakcji w Pyramid. Chcę, aby mój obiekt był możliwy do użytku po transakcja została zatwierdzona. Potrzebuję go tylko do odczytu wartości "buforowanej", czyli tych, które były w nim przed dokonaniem transakcji.

Jedyny sposób, w jaki mogłem się zorientować, to owinięcie klasy (lub samych atrybutów), a następnie śledzenie zmian ręcznie (mogłem to zrobić, ale jest to naprawdę brzydkie i wcale nie pythonic).

Czy istnieje sposób, aby zapobiec próbom odświeżenia tych wartości przez SQLAlchemy?

jako odwrotu bym nawet być otwarte tylko powrocie None, o ile powyższy błąd nie zostanie wyrzucony po transakcji, co zostało popełnione

+0

Jakiego rodzaju atrybutem próbujesz przeczytać? – benselme

+0

Jest to 'PickleType', który jest modyfikowany przez moją własną funkcję' MutableDict.as_mutable() '.Ale wygląda na to, że po zatwierdzeniu wszystkie dane zostaną usunięte ze stanów, więc musisz zapytać, jakiekolwiek dane chcesz (może być źle tutaj ...). – javex

Odpowiedz

7

http://docs.sqlalchemy.org/en/latest/orm/session_api.html

myślę szukasz expire_on_commit = False

Wierzę, że to pozwala odłączyć obiekt i nadal go używać. Próba modyfikacji i zatwierdzenia prowadzi jednak do DetachedInstanceError.

+0

To powinna być zaakceptowana odpowiedź. Link musi jednak zostać zaktualizowany do: http://docs.sqlalchemy.org/en/latest/orm/session_api.html – shaffooo

3

spróbuj tego:

DBSession = scoped_session(sessionmaker(extension=ZopeTransactionExtension(), expire_on_commit=False)) 

miałem ten problem zbyt i korzystania expire_on_commit=False rozwiązać mój problem.

5

Można to zrobić dokładnie to (na przykład w celu buforowania), wykonując:

session.expunge(obj) 

Zgodnie z dokumentacją sqlalchemy:

http://docs.sqlalchemy.org/en/rel_1_0/orm/session_api.html?highlight=expire#sqlalchemy.orm.session.Session.expunge

to daje obiekt, który znajduje się w jednorodzinnym państwa, które możesz bezpiecznie używać - musisz pamiętać, że nie będziesz w stanie odczytać właściwości, które wyemitują inne zapytanie, a zatem będą powiązane z relacjami podobnymi do sesji, to skończy się na DetachedInstanceError.

Domyślnie zatwierdzenie wywoła funkcję expire_all(), co oznacza, że ​​wszystkie obiekty odświeżą swój stan podczas odczytu, przez usunięcie ich odłączysz je od sesji, aby po zatwierdzeniu transakcji nie było żadnych kolejnych zapytań.

Odradzam wyłączanie tej funkcji na całym świecie, ponieważ inne komentarze sugerują, że Mike Bayer generalnie sugeruje, że jest to dobry pomysł i rozsądny domyślny dla większości ludzi, który może uratować ci bóle głowy na dłuższą metę.

Po prostu wyniszczaj rzeczy, gdy ich potrzebujesz.

1
@contextmanager 
def make_session_scope(Session): 
    """Provide a transactional scope around a series of operations.""" 
    session = Session() 
    session.expire_on_commit = False 
    try: 
     yield session 
     session.commit() 
    except: 
     session.rollback() 
     raise 
    finally: 
     session.close() 

with make_session_scope(session) as session: 
     query = session.query(model) 
Powiązane problemy