2010-09-30 11 views
11

Estoy implementando una clase de ontología Python que utiliza un back-end de base de datos para almacenar y consultar la ontología. El esquema de la base de datos es fijo (especificado de antemano), pero no sé qué tipo de motor de base de datos se está utilizando. Sin embargo, puedo confiar en el hecho de que la interfaz de Python del motor de base de datos usa Python DB-API 2.0 (PEP 249). Una idea sencilla es dejar que el usuario pase de Connection objeto 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:Python DB-API: cómo manejar diferentes paramstyles?

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 están permitidos para soportar marcadores de parámetros diferentes en las consultas, definidas por el atributo paramstyle del módulo back-end. Por ejemplo, si es paramstyle = 'qmark', la interfaz admite el estilo de signo de interrogación (SELECT * FROM term WHERE id = ?); paramstyle = 'numeric' significa el estilo posicional numérico (SELECT * FROM term WHERE id = :1); paramstyle = 'format' significa el estilo de cadena de formato ANSI C (SELECT * FROM term WHERE id = %s). Si quiero que mi clase sea capaz de manejar diferentes backends de bases de datos, parece que tengo que prepararme para todos los estilos de marcadores de parámetros. Esto parece frustrar todo el propósito de una API DB común para mí, ya que no puedo usar la misma consulta parametrizada con diferentes backends de bases de datos.

¿Hay alguna forma de evitarlo y, de ser así, cuál es el mejor enfoque? La DB API no especifica la existencia de una función de escape genérica con la que puedo desinfectar mis valores en la consulta, por lo que hacer el escape manualmente no es una opción. No quiero agregar una dependencia adicional al proyecto, ya sea mediante el uso de un nivel aún más alto de abstracción (SQLAlchemy, por ejemplo).

Respuesta

1

Estrictamente hablando, el problema no es causado por la API DB que lo permite, sino por las diferentes bases de datos que usan diferentes sintaxis SQL. El módulo DB API pasa la cadena de consulta exacta a la base de datos, junto con los parámetros. La "resolución" de los marcadores de parámetros la realiza la propia base de datos, no el módulo DB API.

Eso significa que si quieres resolver esto, debes introducir algunos mayor nivel de abstracción. Si no desea agregar dependencias adicionales, tendrá que hacerlo usted mismo. Pero en lugar de escanear y sustituir manualmente, puede tratar de reemplazar dinámicamente los marcadores de parámetros en la cadena de consulta con los marcadores de parámetros deseados, en función del paramstyle del módulo backend. Luego pase la secuencia, CON marcadores de parámetros a la base de datos. Por ejemplo, puede usar '% s' en todas partes y usar la sustitución de cadena de pitón para reemplazar '% s' por ': 1', ': 2', etc. si el db usa el estilo 'numérico', etc. ..

+1

Hmm, no estoy 100% seguro de que el módulo DB API pase la cadena de consulta exacta a la base de datos; por ejemplo, 'BaseCursor.execute' en el módulo' MySQLdb' utiliza 'query = query% db.literal (args)' para formatear la cadena de consulta explícitamente antes de enviarla al motor de DB. Sin embargo, esto podría no ser cierto para otros motores de DB. De todos modos, también me inclino por reemplazar '% s' con otros estilos de marcador explícitamente, sobre la marcha, pero me preguntaba si existe una solución más simple. Si a nadie se le ocurre algo más, aceptaré felizmente tu respuesta. –

+1

"* El módulo DB API pasa la cadena de consulta exacta a la base de datos, junto con los parámetros. *" No creo que ese sea el caso en absoluto. Si nos fijamos en [la especificación de red de PostgreSQL, por ejemplo] (http://www.postgresql.org/docs/8.4/static/protocol-flow.html#PROTOCOL-FLOW-EXT-QUERY), cuando se usa, las consultas de param utilizan ' $ 1', '$ 2', ... como marcadores de posición, que no son ninguno de los [paramstyles de Python] (http://www.python.org/dev/peps/pep-0249/#paramstyle). Claramente, las cadenas de consulta se modifican antes de enviarse, de una forma u otra, más aún cuando se usa un estilo param que se basa en un dict (con nombres). – Bruno

5
  • This Python recipe podría ser capaz de ayudar. Introduce una capa adicional de abstracción para ajustar los parámetros en su propia clase Param.

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

+1

Ambas opciones se ven bien, pero tenga en cuenta que parecen ser viejas. Esas páginas web de códigos fuente muestran los últimos comentarios/actualizaciones de 2004-2007. Eso puede estar bien. Solo ten en cuenta. – IcarusNM

0

no quiero añadir una dependencia adicional para el proyecto, ya sea mediante el uso de un nivel aún más alto de abstracción (SQLAlchemy, por ejemplo).

Eso es muy malo, porque SQLAlchemy sería una solución perfecta para este problema. En teoría, DB-API 2.0 está diseñado para ofrecer este tipo de flexibilidad. Pero eso requeriría que cada desarrollador de controladores (para Oracle, MySQLdb, Postgres, etc.) implemente todos los diferentes parámetros en sus controladores. Ellos no. Así que te quedas atascado con el paramstyle "preferido" para cada motor de base de datos.

Si se rehúsa a utilizar SQLAlchemy o cualquier otra capa de abstracción superior o una biblioteca de clases MVC moderna, sí debe escribir su propio nivel de abstracción más alto para esto. No lo recomiendo, a pesar de que es su solución elegida aquí. Te enfrentas a algunos detalles diabólicos y perderás tiempo averiguando los errores que otros ya han resuelto.

No vea una dependencia de biblioteca externa como algo malo. Si ese es su enfoque de Python, se perderá algunas de las características más poderosas del lenguaje.

Elija su veneno.

Cuestiones relacionadas