DB-API – Qué es y cómo funciona



Versión: todas.

A lo largo de su estadía en el hotel del lenguaje encontrarán, en muchas ocasiones, referencias a la Python DB API 2.0, en especial si realizar trabajos con bases de datos se hace una tarea muy común. Este artículo lo escribo para aquellos que ignoran el término, han sido curiosos y han querido obtener conocimiento, introducirse y/o profundizar el tema.

La Python DB API, actualmente en su versión 2.0, es un conjunto de clases y funciones comunes, estandarizadas, similares para los distintos motores de bases de datos o wrappers alrededor de estos, escritos en Python. Se desarrolla con la finalidad de lograr la consistencia entre todos estos módulos, y ampliar las posibilidades de crear código portable entre las distintas bases de datos. Por ejemplo, si planeas desarrollar un sistema de creación de foros / comunidades (como phpBB, MyBB o SMF) podrás incorporarle la característica de soportar múltiples bases de datos: MySQL, PostgreSQL, SQLite, por nombrar algunas. Cabe aclarar que la API trata de bases de datos SQL, relacionales, principalmente. Implementarla, en lo posible, en motores NoSQL no sería conveniente.

¿Cómo?

Ya hemos visto el qué del artículo. Seguramente tu segunda pregunta será cómo se hace posible esto. Muchos ya lo habrán deducido.

Al momento de desarrollar tu propia librería, módulo o framework, tú decides cómo implementar las funciones y clases que desees exportar y, en base a esto, escribes el código. En el caso de los módulos para base de datos, el mecanismo es inverso. El documento denominado PEP 249 — Python Database API Specification v2.0 indica cómo debe ser la API de tu proyecto; en base a esto decidirás si deseas implementarlo de tal manera o no, y desarrolladores de otros módulos estarán en tu misma situación. Una vez finalizado, todos los paquetes serán similares y el programador estará familiarizado con cada uno de ellos. Hasta el momento no he conocido ningún módulo en relación al tema que no siga estaespecificación, un dato para ayudarte a decidir.

El artículo no pretende indicar cómo implementar el API, de esto se encarga el PEP 249, pero sí citar algunas funciones para ilustrar. Por ejemplo, todos los módulos realizan la conexión a través del mismo método:

connect( parameters... ) – Constructor para crear una conexión a la base de datos. Retorna un objeto del tipo Connection. Toma un conjunto de argumentos que son propios de cada base de datos.

De esta manera, tanto para SQLite como para PostgreSQL sabremos cómo comenzar: llamando a la función connect del módulo.

Para ejecutar una consulta, se crea un cursor, terminología común que se utiliza en la API, haciendo referencia a un objeto encargado de realizar las consultas SQL y retornar el resultado. Por ejemplo:

from module import connect

conn = connect(...)  # Siempre utilizamos connect
cursor = conn.cursor()  # Siempre se crea un cursor llamando a Connection.cursor().

Todos los paquetes que se basen en esta API se inicializarán de la misma manera (código anterior), sin excepciones. Hay otras cláusulas del documento que son opcionales.

# Ejecutamos una consulta utilizando la función execute del cursor.
q = cursor.execute("SELECT nombre, apellido FROM clientes")

En este caso, el uso de la función execute para ejecutar una consulta SQL es común en todas las bases de datos. Sin embargo, el valor de retorno no está estrictamente definido, depende de cada paquete.

# Iteramos entre los resultados
for nombre, apellido in cursor.fetchall():
    print(nombre + ", " + apellido)

Un simple ejemplo para imprimir los resultados de la consulta.

Con respecto a las excepciones, todos los paquetes lanzan ProgrammingError cuando se produce un error en la consulta SQL, se pasaron erróneamente los parámetros, entre otras, y solo por citar un ejemplo. Existen muchas más excepciones comunes: InterfaceError, DatabaseError, DataError, OperationalError, y más.

Por último, la forma común para cerrar una conexión luego de realizar todas las operaciones deseadas es:

conn.close()

Simplemente una pequeña recorrida (muy pequeña) a lo largo del API que propone Python para los módulos o paquetes (los he tomado como sinónimos en este artículo) que correspondan a un motor de base de datos SQL.

Ejemplos

Volviendo al ejemplo del foro, puede tomarse el siguiente pseudocódigo (dado que sólo es una base para la real implementación) para el soporte de múltiples bases de datos:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Constantes
MYSQL = 0
POSTGRESQL = 1
SQLITE = 3
MSSQL = 4

# Determinar el motor seleccionado
database_engine = load_database_engine()

# Cargar el módulo correspondiente
if database_engine == MYSQL:
    import MySQLdb
    engine = MySQLdb
elif database_engine == POSTGRESQL:
    import psycopg2
    engine = psycopg2
elif database_engine == SQLITE:
    import sqlite3
    engine = sqlite3
elif database_engine == MSSQL:
    import pyodbc
    engine = pyodbc
else:
    print("No se ha encontrado %s." % str(database_engine))

# Conectar y crear el cursor.
conn = engine.connect()
cursor = conn.cursor()

# Ejecutar consulta.
cursor.execute("SELECT nombre, apellido FROM clientes")

# Cerrar conexión.
conn.close()



2 comentarios.

  1. Leonardo Caballero says:

    Al reproducir el ejemplo del código que tienes aquí indica el siguiente error:

    $ python2 dbapi.py
    Traceback (most recent call last):
    File «dbapi.py», line 11, in
    database_engine = load_database_engine()
    NameError: name ‘load_database_engine’ is not defined

Deja un comentario