Python DB-API: как обрабатывать различные парамстили?

я реализую класс онтологии Python, который использует бэкэнд базы данных для хранения и запроса онтологии. Схема базы данных фиксирована (указана заранее), но я не знаю, какой тип компонента database engine используется. Однако я могу положиться на то, что интерфейс Python компонента database engine использует Python DB-API 2.0 (PEP 249). Простая идея-позволить пользователю передать PEP 249-совместимый Connection объект конструктора моей онтологии, который будет затем используйте различные жестко закодированные SQL-запросы для запроса базы данных:

class Ontology(object):
    def __init__(self, connection):
        self.connection = connection

    def get_term(self, term_id):
        cursor = self.connection.cursor()
        query = "SELECT * FROM term WHERE id = %s"
        cursor.execute(query, (term_id, ))
        [...]

моя проблема в том, что разные бэкэнды базы данных могут поддерживать разные маркеры параметров в запросах, определенных из модуля. Например, если paramstyle = 'qmark', интерфейс поддерживает стиль вопросительного знака (SELECT * FROM term WHERE id = ?); paramstyle = 'numeric' означает числовой, позиционный стиль (SELECT * FROM term WHERE id = :1); paramstyle = 'format' означает стиль строки формата ANSI C (SELECT * FROM term WHERE id = %s). Если я хочу, чтобы мой класс мог для обработки различных бэкэндов базы данных, похоже, мне нужно подготовиться ко всем стилям маркеров параметров. Это, похоже, разрушает всю цель общего API DB для меня, поскольку я не могу использовать один и тот же параметризованный запрос с разными бэкэндами базы данных.

есть ли способ обойти это, и если да, то каков наилучший подход? API DB не указывает на существование универсальной экранирующей функции, с помощью которой я могу санировать свои значения в запросе, поэтому экранирование вручную не является выбор. Я не хочу добавлять дополнительную зависимость к проекту, используя еще более высокий уровень абстракции (например, SQLAlchemy).

3 ответов


строго говоря, проблема вызвана не API DB, позволяющим это, а различными базами данных, которые используют разные синтаксисы SQL. Модуль DB API передает точную строку запроса в базу данных вместе с параметрами. "Разрешение" маркеров параметров выполняется самой базой данных, а не модулем DB API.

Это означает, что если вы хотите решить эту проблему, вы должны ввести некоторые высокий уровень абстракции. Если вы не хотите добавлять дополнительные зависимости, вам придется сделать это самостоятельно. Но вместо того, чтобы вручную экранировать и заменять, вы можете попытаться динамически заменить маркеры параметров в строке запроса желаемыми маркерами параметров на основе paramstyle бэкэнд-модуля. Затем передайте строку с маркерами параметров в БД. Например, вы можете использовать "%s "везде и использовать подстановку строк python для замены "%s "на": 1",": 2 " и т. д. если БД использует "числовой" стиль и так далее....



Я не хочу добавлять дополнительную зависимость к проекту, используя еще более высокий уровень абстракции (например, SQLAlchemy).

это очень плохо, потому что SQLAlchemy будет идеальным решением для этой проблемы. Теоретически DB-API 2.0 создан для обеспечения такой гибкости. Но для этого потребуется, чтобы каждый разработчик драйверов (для Oracle, MySQLdb, Postgres и т. д.) реализовал все различные стили paramstyles в своих драйверах. Они не знают. Так ты ... застрять с "предпочтительным" paramstyle для каждого ядра СУБД.

Если вы отказываетесь использовать SQLAlchemy или любой другой более высокий уровень абстракции или современную библиотеку классов MVC, да, вы должны написать свой собственный более высокий уровень абстракции для этого. Я не рекомендую этого, несмотря на то, что это ваше выбранное решение здесь. Вы столкнулись с некоторыми дьявольскими деталями там, и будет тратить время на выяснение ошибок, которые другие уже решили.

не просматривать зависимость внешней библиотеки как плохо. Если это ваш подход к Python, вам будет не хватать некоторых из самых мощных функций языка.

выбрать свой яд.