我正在编写一些帐户创建代码并尝试捕获特定的sqlalchemy异常,这样当用户使用已经与现有帐户关联的电子邮件注册帐户时,我就可以反馈相应的错误消息。 / p>
我希望在发生这种情况时能够获得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": "a@b.com"
}
然后使用不同的userId再次发布,但同样的电子邮件:
{
"userId": "Bob",
"email": "a@b.com"
}
我希望第二篇文章引发IntegrityError,但我发现它引发了一个ProgrammingError:
sqlalchemy.exc.ProgrammingError: (pg8000.core.ProgrammingError)
('ERROR',
'23505',
'duplicate key value violates unique constraint "idx_email"',
'Key (email)=(a@b.com) 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', 'a@b.com')]
我错过了什么?
答案 0 :(得分:4)
不幸的是,当遇到DBAPI错误时,SQLAlchemy只包装了底层dbapi兼容库引发的异常。
也就是说,SQLAlchemy仅提出ProgrammingError
,因为pg8000
选择引发ProgrammingError
。
如果您一直使用psycopg2
来管理基础连接,那么您的错误就会表现为IntegrityError
(正如预期的那样)。
根据pg8000
documentation,它永远不会引发IntegrityError
。事实上,它不会提出以下任何内容:
这里的教训是,当涉及到数据库级错误时,您无法保证SQLAlchemy将在不同的dbapi连接器中抛出的类型。