Обработка ошибок 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 ....