Python DB-API: как обрабатывать разные paramstyles?

Я реализую класс онтологии Python, который использует бэкэнд базы данных для хранения и запроса онтологии. Схема базы данных фиксирована (заранее задана), но я не знаю, какой тип механизма базы данных используется. Однако я могу положиться на то, что интерфейс Python для механизма базы данных использует Python DB-API 2.0 ( PEP 249 ). Прямая идея состоит в том, чтобы позволить пользователю передать объект Connection совместимый с PEP 249, с конструктором моей онтологии, который затем будет использовать различные жестко запрограммированные 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 модуля backend. Например, если 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 БД для меня, поскольку я не могу использовать тот же параметризованный запрос с разными базами данных базы данных.

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

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

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

  • Этот рецепт Python может помочь. Он вводит дополнительный слой абстракции для переноса параметров в свой собственный класс Param .

  • Проект PyDal также может быть ближе к тому, что вы пытаетесь достичь: « PyDal позволяет использовать те же типы paramstyle и datetime с любым модулем, который соответствует DBAPI 2.0. Кроме того, параметры paramstyles и datetime настраиваются ».

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

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

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

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

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