2016-08-25 2 views
3

いくつかのアカウント作成コードを書き、特定のsqlalchemy例外をキャッチしようとしているため、ユーザーが既存のアカウントに既に関連付けられている電子メールにアカウントを登録するときに、適切なエラーメッセージを返すことができます。なぜsqlalchemy.exc.IntegrityErrorではなくsqlalchemy.exc.ProgrammingErrorが得られますか?

これが起こったときにIntegrityErrorが発生することを期待していましたが、代わりにProgrammingErrorを取得しています。私は喜んで代わりにProgrammingErrorをキャッチすることができましたが、なぜ私が期待していたものが得られないのか理解しようとしています。

私は明確にするため、モデルとコードを削減しましたが、モデルは次のようになります。

from service import db 
from sqlalchemy import Index 

class UserProfile(db.Model): 
user_id = db.Column(db.String(255), nullable=False, primary_key=True) 
email = db.Column(db.String(255), nullable=False) 

def __init__(self, account_data): 
    self.user_id = account_data['userId'] 
    self.email = account_data['email'].lower() 

def __repr__(self): 
    return 'UserID-{}, Email-{}'.format(self.user_id,self.email)                    

Index('idx_email', UserProfile.email, unique=True) 

とコードの主なビットは、次のようになります。私はポストのであれば

@app.route('/create_account', methods=['POST']) 
def create_account(): 

account_data = request.get_json() 

account_details = UserProfile(account_data) 
try: 
    db.session.add(account_details) 
    db.session.flush() 

    # do stuff 

    db.session.commit() 

except ProgrammingError as err: 
    db.session.rollback() 
    if "duplicate key value violates unique constraint \"idx_email\"" in str(err): 
     LOGGER.error('Email address already in use!' 

例えば、いくつかのJSON:

{ 
    "userId": "Fred", 
    "email": "[email protected]" 
} 

し、別のuserIdが、同じメールを再び投稿:

{ 
    "userId": "Bob", 
    "email": "[email protected]" 
} 

私はIntegrityErrorを高めるために第2のポストを期待するだろうが、私はそれがProgrammingErrorを上げる見ている:

sqlalchemy.exc.ProgrammingError: (pg8000.core.ProgrammingError) 
('ERROR', 
'23505', 
'duplicate key value violates unique constraint "idx_email"', 
'Key (email)=([email protected]) already exists.', 
'public', 
'user_profile', 
'idx_email', 
'nbtinsert.c', 
'406', 
'_bt_check_unique', '', '') 
[SQL: 'INSERT INTO user_profile (user_id, email) VALUES (%s, %s)'] 
[parameters: ('Bob', '[email protected]')] 

私は何をしないのですか?

答えて

3

残念ながら、DBAPIエラーの場合、SQLAlchemyは基礎となるdbapi互換ライブラリによって発生した例外を単にラップします。ある

pg8000ProgrammingErrorを高めることを選んだので、SQLAlchemyのは特にProgrammingErrorを発生させます。

psycopg2を使用して基本接続を管理していた場合、エラーはIntegrityError(期待どおり)として現れます。

pg8000 documentationによれば、IntegrityErrorは発生しません。実際には、次のいずれも発生しません。

  • IntegrityError;
  • DataError;
  • DatabaseError;
  • OperationalError;

ここで教訓は、データベースレベルのエラーになると、SQLAlchemyが異なるdbapiコネクタを介して投げるタイプを保証できないということです。

関連する問題