Pregunta

estoy poniendo en práctica un pitón ontología clase que utiliza un motor de base de datos para almacenar y consulta la ontología. El esquema de la base es fija (especificado con antelación), pero no sé lo que se está utilizando el tipo de motor de base de datos. Sin embargo, puedo confiar en el hecho de que la interfaz de Python del motor de base de datos utiliza el DB-API Python 2.0 ( PEP 249 ). Una idea sencilla es dejar que el usuario pase objeto Connection una PEP 249 compatible con el constructor de mi ontología, que a su vez usar varias consultas SQL codificado para consultar la base de datos:

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, ))
        [...]

Mi problema es que los diferentes backends de bases de datos se les permite soportar diferentes marcadores de parámetros en las consultas, definidos por el atributo paramstyle del módulo de servidor. Por ejemplo, si paramstyle = 'qmark', la interfaz es compatible con el estilo signo de interrogación (SELECT * FROM term WHERE id = ?); paramstyle = 'numeric' significa el numérico, estilo posicional (SELECT * FROM term WHERE id = :1); paramstyle = 'format' significa el estilo de formato de cadena ANSI C (SELECT * FROM term WHERE id = %s). Si yo quiero hacer mi clase sea capaz de manejar diferentes backends de bases de datos, parece que tengo que preparar para todos los estilos de parámetros de marcador. Esto parece derrotar todo el propósito de una API de base de datos común para mí, ya que no puedo usar la misma consulta parametrizada con diferentes backends de bases de datos.

¿Hay una manera alrededor de ella, y si es así, ¿cuál es el mejor enfoque? La API DB no especifica la existencia de una función de escape genérico con el que puedo desinfectar mis valores en la consulta, por lo que haciendo el escape de forma manual no es una opción. No quiero añadir una dependencia adicional para el proyecto, ya sea mediante el uso de un mayor nivel de abstracción (SQLAlchemy, por ejemplo).

¿Fue útil?

Solución

En sentido estricto, el problema no es causado por la API de base de datos que permite esto, pero por las diferentes bases de datos que utilizan diferentes sintaxis SQL. El módulo API DB pasa la cadena de consulta exacta a la base de datos, junto con los parámetros. "Resolución" los marcadores de parámetros se realiza mediante la base de datos en sí, no por el módulo API DB.

Esto significa que si se quiere resolver esto, usted tiene que introducir algunos alto nivel de abstracción. Si no desea agregar dependencias adicionales, tendrá que hacerlo usted mismo. Pero en lugar de escapar y sustituyendo de forma manual, se puede tratar de sustituir dinámicamente marcadores de parámetros en la cadena de consulta con los marcadores de parámetros deseados, en base a la paramstyle del módulo de servidor. A continuación, pasar la cadena, con marcadores de parámetros a la db. Por ejemplo, podría utilizar '% s' en todas partes, y la sustitución de cadenas usar Python para reemplazar el '% s' con ': 1', '2', etc. si el estilo de los usos DB 'numérico', y así sucesivamente .. ..

Otros consejos

  • Esta receta Python podría ser capaz de ayuda. Se introduce una capa adicional de abstracción para los parámetros de envoltura en su propia clase Param.

  • El PyDal proyecto también puede estar más cerca de lo que estamos tratando de lograr: "< em> PyDal hace que sea posible el uso de la misma paramstyle y de fecha y hora tipos con cualquier módulo que se ajusta a DBAPI 2,0. Además, paramstyles y de fecha y hora tipos son configurables. "

  

No quiero añadir una dependencia adicional para el proyecto, ya sea mediante el uso de   una aún mayor nivel de abstracción (SQLAlchemy, por ejemplo).

Esto es una lástima, porque SQLAlchemy sería una solución perfecta para este problema. En teoría, DB-API 2.0 está construido para ofrecer este tipo de flexibilidad. Pero eso requeriría que todos los desarrolladores controlador (por Oracle, MySQLdb, Postgres, etc.) para poner en práctica todas las diferentes paramstyles en sus conductores. Ellos no lo hacen. Para que se queden con el paramstyle "preferido" para cada motor de base de datos.

Si se niega a utilizar SQLAlchemy o cualquier otra capa de abstracción más alto o biblioteca de clases MVC moderna, sí se tiene que escribir su propio nivel más alto de abstracción para esto. No recomiendo que, a pesar de que ser su solución elegida aquí. Estás frente a algunos detalles diabólicos allí, y será un desperdicio de tiempo tratando de descifrar los errores que otros ya han resuelto.

No vea una dependencia biblioteca externa como algo malo. Si ese es su enfoque para Python, que va a estar perdiendo algunas de las características más potentes de la lengua.

Escoja su veneno.

Lo que me hizo tropezar aquí era cómo averiguar lo que se requiere paramstyle si su código sólo se pasa un objeto de conexión o el cursor. Esto es lo que ocurrió:

import importlib

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

Probablemente debería hacer más comprobación de la cordura del objeto conn, o al menos terminar con esto en un bloque try, dependiendo de lo que las hipótesis está dispuesto a hacer.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top