it-swarm.com.de

kann SQLAlchemy IntegrityError nicht abfangen

Versuchen Sie, wie ich könnte, ich kann den sqlalchemy IntegrityError scheinbar nicht richtig erfassen:

from sqlalchemy import exc

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

Als was man erwarten könnte:

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

Ich habe ausdrücklich versucht:

from sqlalchemy.exc import IntegrityError

UPDATE:

Ich habe etwas gefunden, das zu dem passt, was hier passiert, wo Integritätsfehler erst ausgelöst wird, wenn die Sitzung in die Datenbank geschrieben wurde und nachdem die try/exceptblocks ausgeführt wurden: Versuch, Integritätsfehler mit SQLAlchemy abzufangen

Das Hinzufügen von session.flush() im Block try ergibt jedoch eine 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)
20
Chrispy

Sobald der IntegrityError ausgelöst wird, ist die Sitzung, in der Sie gerade gearbeitet haben, ungültig, unabhängig davon, ob Sie den Fehler erkannt haben oder nicht. Da die zweite Fehlermeldung Sie dazu auffordert, To begin a new transaction with this Session, first issue Session.rollback()., die Sitzung weiter zu verwenden, müssen Sie eine session.rollback() ausgeben.

Ich kann es nicht mit Sicherheit sagen, aber ich vermute, Sie oder Ihr Web-Framework versucht, die Sitzung weiterzuverwenden, die den IntegrityError in gewisser Weise ausgelöst hat. Ich empfehle Ihnen, eine session.rollback() auszugeben, nachdem Sie die Ausnahme abgefangen haben, oder in Ihrer handle_elegantly-Funktion. 

Wenn Sie das unten ausführen, sehen Sie, was ich meine:

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):
    __table= '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 __== '__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")
19
Jason

Ich habe das gleiche Bedürfnis in meiner Flask-Anwendung, ich verfahren wie unten und es funktioniert:

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()
16
JsonBruce

SQLALCHEMY_COMMIT_ON_TEARDOWN = False

0
ivan