[Python-es] Pyramid + SQLAlchemy + commit() inoportuno

Miguel Sanchez miguel en mariaonline.org
Lun Oct 17 18:31:36 EDT 2022


Hola lista.

Me contesto a mi mismo, por si alguien se encuentra con este mismo asunto.

El tema no está tanto en la sesión de SQLAlchemy, sino en el manejo de las transacciones que hace Pyramid (tal como queda configurado usando su cookiecutter recomendado para hacer un proyecto básico [1])

En estas circunstancias las transacciones las maneja el módulo transaction[2] tal como lo configura pyramid_tm[3] y leyendo este código fuente he podido hacerme una idea de como tratar la situación:
Usando request.tm.doom() en lugar de request.dbsession.rollback() he conseguido que las cosas funcionen como quería (eso creo).

Saludos

Miguel Sánchez


[1] https://github.com/Pylons/pyramid-cookiecutter-starter
[2] https://github.com/zopefoundation/transaction
[3] https://github.com/Pylons/pyramid_tm/blob/master/src/pyramid_tm/__init__.py


El Sun, 9 Oct 2022 12:50:56 +0100
Miguel Sanchez <msanchez en uninet.edu> dijo:

> Hola Lista.
> 
> Estoy comenzando con Pyramid + SQLAlchemy y me he atascado.
> 
> Es posible que esté haciendo varias cosas mal al mismo tiempo. Les digo cómo lo estoy haciendo:
> 
> He definido los modelos, según la documentación recomienda (creo):
> 
> class Mitabla(Base):
>     __tablename__ = 'mitabla'
>     id = Column(Integer, primary_key=True)
>     dato1 = Column(Integer)
> 
>     def __init__(self, dato1):
>         self.dato1 = dato1
> 
>     def __setattr__(self, attr, valor):
>         if attr == 'dato1':
>             if not isinstance(int(valor), int):
>                 raise ValueError('dato1 no es un int')
>         super().__setattr__(attr, valor)
> 
> 
> Como pueden ver uso __setattr__ para filtrar los valores que se pueden asignar a las columnas.
> 
> He definido una "vista" que va a ser invocada desde un ajax y que espero me devuelva unos valores json:
> 
> @view_config(route_name='haceralgo',
>              http_cache=0,
>              renderer='json'
>              )
> def haceralgo(request):
> 
> En dicha vista tengo varios executes a la sesion del request (request.dbsession)
> Unos seleccionan datos, otras borran, otras actualizan
> 
> Esto funciona perfectamente, genero una respuesta json y los datos quedan modificados/borrados
> 
> try:
>     sentencia = select( ....
>     resultado = request.dbsession.execute(sentencia).scalar_one()
>     sentencia = delete( ....
>     request.dbsession.execute(sentencia)
>     sentencia = select( ...
>     resultado2 = request.dbsession.execute(sentencia).scalar_one()
>     resultado2.dato1 = 100
> 
>     return Response(.....
> except ....
> 
> El problema aparece cuando hay un error y quiero capturarlo .... por ejemplo  haciendo que resultado2.dato1 = 'No sea un entero' o simplemente metiendo un 1/0 en el try ... except
> 
> Mi idea es capturar el error, loguearlo y enviar un json informando del error
> 
> Si hago:
> except Exception as error:
>     request.dbsession.rollback()
>     log.debug(error)
>     raise
> 
> Todo funciona como debería salvo que no respondo a la petición ajax, lo que llega es un error generado por el servidor:
> Internal Server Error
> The server encountered an unexpected internal server error
> (generated by waitress)
> 
> 
> Si hago 
> except Exception as error:
>     log.debug(error)
>     return Response(json.dumps('Datos con el error'),
>                     content_type='application/json; charset=utf-8',
>                     status=500)
> Se genera la respuesta json correctamente
> PERO también se genera un commit() que hace que todas las sentencias del try: donde NO se han generado errores (del tipo que sea) se graben en la base de datos
> Esto es un problema pues la bd se me queda en un estado inconsistente
> 
> 
> Si hago 
> except Exception as error:
>     request.dbsession.rollback()
>     log.debug(error)
>     return Response(json.dumps('Datos con el error'),
>                     content_type='application/json; charset=utf-8',
>                     status=500)
> 
> En el servidor se lanza un error: sqlalchemy.exc.ResourceClosedError: This transaction is closed
> No se genera la respuesta json
> Y llega el mismo error de antes generado por el servidor
> Internal Server Error
> The server encountered an unexpected internal server error
> (generated by waitress)
> 
> 
> 
> 
> Alguna sugerencia???, que hago mal???
> 
> 
> Gracias y saludos
> 
> 
> Miguel Sánchez
> 
> 
> _______________________________________________
> Python-es mailing list
> Python-es en python.org
> https://mail.python.org/mailman/listinfo/python-es


Más información sobre la lista de distribución Python-es