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

StackOverflow https://stackoverflow.com/questions/3829098

  •  26-09-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

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

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

Другие советы

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

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

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

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

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

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

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

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

import importlib

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

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top