DB-API Python: как работать с разными стилями? - PullRequest
13 голосов
/ 30 сентября 2010

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

Ответы [ 4 ]

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

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

2 голосов
/ 30 сентября 2010

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

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

0 голосов
/ 01 мая 2019

Меня поразило то, как выяснить, какой параметр стиля требуется, если вашему коду просто передается объект соединения или курсор. Вот что я придумал:

import importlib

def get_paramstyle(conn):
    name = conn.__class__.__module__.split('.')[0]
    mod = importlib.import_module(name)
    return mod.paramstyle

Вы, вероятно, должны сделать больше проверки работоспособности объекта conn или, по крайней мере, обернуть это в блок try, в зависимости от того, какие предположения вы готовы сделать.

0 голосов
/ 23 апреля 2014

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

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

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

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

Собери свой яд.

...