19

エラーをキャッチしようとすると問題が発生します。私は Pyramid/SQLAlchemy を使用しており、電子メールを主キーとしてサインアップ フォームを作成しました。問題は、重複した電子メールが入力されると IntegrityError が発生することです。そのため、そのエラーをキャッチしてメッセージを提供しようとしていますが、何をしてもキャッチできず、エラーが表示され続けます。

try:
    new_user = Users(email, firstname, lastname, password)
    DBSession.add(new_user)
    return HTTPFound(location = request.route_url('new'))
except IntegrityError:
    message1 = "Yikes! Your email already exists in our system. Did you forget your password?"

試したときに同じメッセージが表示されますexcept exc.SQLAlchemyError(ただし、すべてを包括的にキャッチするのではなく、特定のエラーをキャッチしたいのですが)。私も試しexc.IntegrityErrorましたが、うまくいきませんでした(APIには存在しますが)。

Python 構文に何か問題がありますか、それともそれをキャッチするために SQLAlchemy で何か特別なことをする必要がありますか?


この問題を解決する方法はわかりませんが、問題の原因についていくつかのアイデアがあります。SQLAlchemy 自体が例外を発生させ、Pyramid がビューを生成しているため、try ステートメントは失敗していませんが成功している可能性がありますexcept IntegrityError:。または、おそらく、このエラーを完全に間違って認識しています。

4

6 に答える 6

23

Pyramid では、 を使用するようにセッションを構成した場合 (スキャフォールドが自動的に行います) ZopeTransactionExtension、ビューが実行されるまでセッションはフラッシュ/コミットされません。ビューで SQL エラーを自分でキャッチしたい場合は、強制的flushに SQL をエンジンに送信する必要があります。DBSession.flush()の後に行う必要がありますadd(...)

アップデート

トランザクションパッケージでこれを行う方法の例がほとんどないという理由だけで、セーブポイントの例でこの回答を更新しています。

def create_unique_object(db, max_attempts=3):
    while True:
        sp = transaction.savepoint()
        try:
            obj = MyObject()
            obj.identifier = uuid.uuid4().hex
            db.add(obj)
            db.flush()
        except IntegrityError:
            sp.rollback()
            max_attempts -= 1
            if max_attempts < 1:
                raise
        else:
            return obj

obj = create_unique_object(DBSession)

テーブルレベルのロックが使用されていない場合、これでもトランザクション間の重複の影響を受けやすいことに注意してください。ただし、少なくともセーブポイントの使用方法を示しています。

于 2012-07-03T17:27:59.797 に答える
8

必要なことは、一般的な例外をキャッチしてそのクラスを出力することです。次に、例外をより具体的にすることができます。

except Exception as ex:
    print ex.__class__
于 2012-07-03T16:23:02.070 に答える
5

DBSession.commit()したがって、すでに戻ってきIntegrityErrorたコントローラーコードの後で、スタックの後半でが発生するまで、データベース操作がない可能性があります。try/except

于 2012-07-03T16:49:49.857 に答える
1

これが私のやり方です。

from contextlib import(
        contextmanager,
        )


@contextmanager
def session_scope():
    """Provide a transactional scope around a series of operations."""
    session = Session()
    try:
        yield session
        session.commit()
    except:
        session.rollback()
        raise
    finally:
        session.close()



def create_user(email, firstname, lastname, password):

    new_user = Users(email, firstname, lastname, password)

    try:

        with session_scope() as session:

            session.add(new_user)

    except sqlalchemy.exc.IntegrityError as e:
        pass

http://docs.sqlalchemy.org/en/latest/orm/session_basics.html#when-do-i-construct-a-session-when-do-i-commit-it-and-when-do-i-閉じる

于 2015-05-20T21:22:56.597 に答える