2013-03-13 3 views
10

Ich möchte eine Instanz einer Klasse von meiner Sitzung trennen, sie sollte jedoch weiterhin zum Lesen verfügbar sein (ohne eine Abfrage auszugeben). Ich habe jetzt Tage die Dokumentation Scannen durch, aber jeder Ansatz, den ich versuche, führt zu der NachrichtTrennen der SQLAlchemy-Instanz, so dass keine Aktualisierung stattfindet

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

ich mit dem zope.sqlalchemy Transaktions-Manager bei Pyramid arbeite. Ich möchte, dass mein Objekt verwendbar ist nach die Transaktion wurde festgeschrieben. Ich brauche es nur, um den "zwischengespeicherten" Wert zu lesen, d. H. Diejenigen, die vor dem Commit der Transaktion darin waren.

Die einzige Möglichkeit, die ich herausfinden konnte, war, die Klasse (oder die Attribute selbst) zu wickeln und dann Änderungen manuell zu verfolgen (ich könnte das tun, aber es ist wirklich hässlich und überhaupt nicht pythonisch).

Gibt es eine Möglichkeit, SQLAlchemy daran zu hindern, diese Werte zu aktualisieren?

Als Absicherung ich auch offen sein würde, nur None zurückkehren, solange der obige Fehler nicht nach der Transaktion geworfen bekommen als

+0

Welche Art von Attribut versuchen Sie zu lesen? – benselme

+0

Es ist ein 'PickleType', der durch meine eigene' MutableDict.as_mutable() '-Funktion veränderbar gemacht wird.Aber es scheint, sobald ein Festschreiben passiert, werden alle Daten aus den Zuständen entfernt, so dass Sie abfragen müssten, was auch immer Sie wollen (könnte aber hier falsch sein ...) – javex

Antwort

7

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

begangen worden glaube ich Sie suchen expire_on_commit = False

Ich glaube, dies ermöglicht es Ihnen, das Objekt zu lösen und weiterhin zu verwenden. Der Versuch, es zu modifizieren und zu committen, wird jedoch zum DetachedInstanceError führen.

+0

Dies sollte die akzeptierte Antwort sein. Der Link muss jedoch aktualisiert werden auf: http://docs.sqlalchemy.org/en/latest/orm/session_api.html – shaffooo

3

versuchen Sie dies:

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

Ich habe dieses Problem auch und mit expire_on_commit=False mein Problem gelöst.

5

Sie können genau dies tun (zum Beispiel für das Caching), indem Sie:

session.expunge(obj) 

Per sqlalchemy Dokumentation:

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

Dies wird Ihnen Objekt, das in abgenommenen Zustand ist, dass Sie können sicher verwenden - Sie müssen sich daran erinnern, dass Sie keine Eigenschaften lesen können, die eine andere Abfrage ausgeben würden und somit an eine sitzungsähnliche Beziehung gebunden wären. Dies endet mit DetachedInstanceError.

Standardmäßig wird ein Commit ein expire_all() ausgeben, was bedeutet, dass alle Objekte ihren Status beim Lesen aktualisieren, indem sie sie von der Sitzung trennen, so dass es keine nachfolgenden Abfragen geben sollte, nachdem Sie Ihre Transaktion festgeschrieben haben.

Ich würde davon abraten, diese Funktionalität global zu deaktivieren, wie die anderen Kommentare vorschlagen, wie Mike Bayer im Allgemeinen vorschlägt, es ist eine gute Idee und ein vernünftiger Standard für die meisten Menschen, die Sie Kopfschmerzen auf lange Sicht sparen können.

Löschen Sie Dinge einfach explizit, wenn Sie sie brauchen.

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) 
Verwandte Themen