python exception exception-handling error-handling sqlalchemy

python - no puede capturar SQLAlchemy IntegrityError



exception exception-handling (3)

SQLALCHEMY_COMMIT_ON_TEARDOWN = Falso

Por más que lo intente, parece que no puedo capturar correctamente el IntegrityError sqlalchemy:

from sqlalchemy import exc try: insert_record() except exc.IntegrityError, exc: print exc # this is never called handle_elegantly() # this is never called

Como lo que uno podría esperar:

IntegrityError: (IntegrityError) insert or update on table "my_table" violates foreign key constraint "my_table_some_column_fkey"

He intentado explícitamente:

from sqlalchemy.exc import IntegrityError

ACTUALIZAR:

Encontré algo que parece encajar en lo que está sucediendo aquí, donde el error de integridad no se produce hasta que la sesión se vacía en la base de datos, y después de que se ejecutan los bloques de try / except : tratando de detectar el error de integridad con SQLAlchemy

Sin embargo, al agregar session.flush() en el bloque try se obtiene un InvalidRequestError :

ERROR:root:This Session''s transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (IntegrityError)


Tan pronto como se IntegrityError , independientemente de si ha detectado el error o no, la sesión en la que estaba trabajando se invalida. Como el segundo mensaje de error le indica: To begin a new transaction with this Session, first issue Session.rollback(). , para continuar usando la sesión necesitarás emitir una session.rollback()

No puedo decirlo con certeza, pero supongo que usted o su marco de trabajo web intentan continuar utilizando la sesión que provocó IntegrityError de alguna manera. Le recomiendo que emita un session.rollback() después de detectar la excepción o en su función handle_elegantly .

Si ejecuta el siguiente verás lo que quiero decir:

from sqlalchemy import types from sqlalchemy import exc from sqlalchemy import create_engine from sqlalchemy.schema import Column from zope.sqlalchemy import ZopeTransactionExtension from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import sessionmaker, scoped_session Base = declarative_base() class User(Base): __tablename__ = ''user'' name = Column(types.String, primary_key=True) def handle_elegantly(name): session = DBSession() session.add(User(name=name)) session.flush() print ''Exception elegantly handled!!/n'' def pretend_view(request): """Pretend view in a Pyramid application using pyramid_tm""" session = DBSession() user = User() print ''/n-------Here we rollback before continuing -------'' try: session.add(user) session.flush() except exc.IntegrityError: session.rollback() handle_elegantly(''This will run fine'') print ''/n------- Here we do not, and this will error -------'' try: session.add(user) session.flush() except exc.IntegrityError: handle_elegantly(''Exception will be raised'') if __name__ == ''__main__'': engine = create_engine(''sqlite://'') global DBSession DBSession = scoped_session( sessionmaker(extension=ZopeTransactionExtension())) DBSession.configure(bind=engine) Base.metadata.bind = engine Base.metadata.create_all() pretend_view("dummy request")


Tengo la misma necesidad en mi aplicación Flask, la manejo como se muestra a continuación y funciona:

from flask import Flask from flask_sqlalchemy import SQLAlchemy from sqlalchemy import exc db = SQLAlchemy(Flask(__name__)) try: db.session.add(resource) return db.session.commit() except exc.IntegrityError as e: db.session().rollback()