python - create_engine - sqlalchemy tutorial español
SQLAlchemy, obtén objeto no vinculado a una Sesión (3)
Por diversas razones, estoy tratando de obtener una colección de objetos de una base de datos y pasarla a otro proceso que no está conectado a la base de datos. Mi código se parece al siguiente pero sigo recibiendo
sqlalchemy.exc.UnboundExecutionError: Instance <MyClass at 0x8db7fec> is not bound to a Session; attribute refresh operation cannot proceed
Cuando trato de ver los elementos de mi lista fuera del método get_list()
.
def get_list (obj):
sesson = Session()
lst = session.query(MyClass).all()
session.close()
return lst
Sin embargo, si uso esto
def get_list_bis (obj)
session = Session()
return session.query(MyClass).all()
Puedo usar los elementos pero me preocupa el estado de la sesión ya que no estaba cerrada.
¿Que me estoy perdiendo aqui?
En mi caso, estaba guardando una entidad relacionada también, y esta receta me ayudó a refresh todas las instancias dentro de una sesión, aprovechando el hecho de que Session es iterable:
map(session.refresh, iter(session)) # call refresh() on every instance
Esto es extremadamente ineficaz, pero funciona. Debería estar bien para pruebas unitarias.
Nota final: en Python3 map()
es un generador y no hará nada. Use bucles reales de listas de comprensión
Esto ocurre a menudo debido a que los objetos están en estado expired
, los objetos caducan, por ejemplo, después de la committing , cuando los objetos caducados están a punto de utilizarse, ORM intenta refresh
, pero esto no se puede hacer cuando los objetos se separan de la sesión (porque la sesión fue, por ejemplo, cerrada ). Este comportamiento se puede gestionar creando una sesión con expire_on_commit=False
param.
>>> from sqlalchemy import inspect
>>> insp = inspect(my_object)
>>> insp.expired
True # then it will be refreshed...
Si desea que un conjunto de objetos generados al consultar una sesión sean utilizables fuera del alcance de la sesión, debe expunge para la sesión.
En tu primer ejemplo de función, necesitarás agregar una línea:
session.expunge_all()
antes de
session.close()
De manera más general, digamos que la sesión no se cierra de inmediato, como en el primer ejemplo. Quizás esta es una sesión que se mantiene activa durante toda la duración de una solicitud web o algo así. En tales casos, no quiere hacer expunge_all
. Querrá ser más quirúrgico:
for item in lst:
session.expunge(item)