Обработка ошибок SQLAlchemy-как это делается?
Я хочу обработать случай, когда есть первичный ключ или уникальный конфликт ключей, он же дубликат записи. Для этого я ловлю IntegrityError
, который ловит ошибку просто отлично. Проблема в том, что я не могу найти простое сообщение об ошибке или код ошибки для проверки. Все, что я получаю, это IntegrityError.message
свойство, которое представляет собой строку, которая выглядит следующим образом:
(IntegrityError) (1062, "дубликат записи 'foobar' для ключа 'name'")
- Это не очень полезно. Используя это, мне придется начать разбор сообщений об ошибках для их кода и сообщения. Зову dir
в исключении отображаются только следующие свойства:
'args', 'connection_invalidated',' instance',' message',' orig',' params','statement'
args-это просто одноэлементный кортеж с вышеупомянутой строкой внутри него, а params-это данные, которые я пытался вставить. Кажется, я не могу найти способ определить, что это действительно дубликат ключевая ошибка без необходимости начинать разбор сообщения об ошибке с помощью regex или чего-то еще.
может ли кто - нибудь пролить свет на этот вопрос?
спасибо
2 ответов
Я понял это во время написания вопроса, прочитав документацию более внимательно. Я все еще собираюсь опубликовать это, так как это может помочь кому-то.
в документации по SQLAlchemy DBAPIError, из которых IntegrityError подкласс, он объясняет, что исключение является просто оболочкой для основной ошибки API базы данных и что исходная ошибка сохраняется как orig
в исключения. Конечно, звоню. e.orig.args
Я получаю хорошо организованный кортеж:
(1062, "дубликат записи' foobar 'для ключа 'name'")
насколько я знаю, единственный способ-парсить строку ошибки в исключения. Я не могу найти кортеж, указывающий ошибку, столбец с нарушенным ограничением уникальности и значением отдельно.
в частности, можно искать сообщение об исключении с помощью оператора поиска подстроки или регулярного выражения. Например:
db.session.add(SupplierUser(supplier_id=supplier_id, username=username, password=password, creator=user))
try:
db.session.commit()
except IntegrityError as err:
db.session.rollback()
if "UNIQUE constraint failed: user.username" in str(err):
return False, "error, username already exists (%s)" % username
elif "FOREIGN KEY constraint failed" in str(err):
return False, "supplier does not exist"
else:
return False, "unknown error adding user"
однако эти строки могут быть довольно длинными, потому что инструкция SQL включена, например:
(sqlite3.IntegrityError) UNIQUE constraint failed: user.username [SQL: 'INSERT INTO user (username, password_hash, created_time, creator_id, role, is_active, supplier_id) VALUES (?, ?, ?, ?, ?, ?, ?)'] [parameters: ('bob', ...
таким образом, вы минимизируете задержки обработки ошибок при анализе исключений при поиске в сообщении об ошибке базы данных без дополнительной информации из sqlalchemy. Это можно сделать путем изучения err.args, который должен быть меньше:
'(sqlite3.IntegrityError) UNIQUE constraint failed: supplier_user.username',)
обновленная пример:
db.session.add(SupplierUser(supplier_id=supplier_id, username=username, password=password, creator=user))
try:
db.session.commit()
except IntegrityError as err:
db.session.rollback()
err_msg = err.args[0]
if "UNIQUE constraint failed: supplier_user.username" in err_msg:
return False, "error, supplier username already exists (%s)" % username
elif "FOREIGN KEY constraint failed" in err_msg:
return False, "supplier does not exist"
else:
return False, "unknown error adding user"
обратите внимание, что синтаксис ошибки, который я использовал здесь, предназначен для sqlite3. Разбор сообщения об ошибке исключения mysql, например:
(1062, "Duplicate entry 'usr544' for key 'username'")
можно сделать с соответствующим регулярным выражением. Обратите внимание, что это выглядит как кортеж, но на самом деле это строка (sqlalchemy версии 1.1.3 и mysql 5.5).
например:
except IntegrityError as err:
db.session.rollback()
if re.match("(.*)Duplicate entry(.*)for key 'username'(.*)", err.args[0]):
.... etc ....