Está en la página 1de 10

Persistencia de imgenes con Python: SQLServer y cPickle

Hola. En este artculo vamos a ver cmo guardar y recuperar imgenes de una base de datos Microsoft SQLServer 2005 Express Edition, con Python, as como guardar y recuperar tambin, imgenes, en un objeto que se serializa, guardando dicha informacin en disco, mediante cPickle. Antes de nada comentar que en este blog se han tratado varios tipos de SGBD, tales como MySQL, Firebird, SQLServer 2008. El elegir SQLServer 2005 Express Edition es simplemente para probar que Pythonfunciona, mediante pyodbc, con la mayora de los sistemas gestores de bases de datos actuales. Y para ver si funciona lo mejor es probarlo uno mismo, ya que no es lo mismo conocer el camino que andar el camino. NOTA: Este post lo he escrito en la plataforma Microsoft Windows XP SP3, con Python 2.6.6.

Imgenes en SQLServer 2005 con Python


Lo primero de todo es descargar el SGBD Microsoft SQLServer 2005 Express Edition.

Se puede hacer desde aqu: http://www.microsoft.com/downloads/details.aspx?FamilyID=220549b5-0b07-44488848-dcc397514b41&displayLang=es Tambin (recomendable) es posible descargarse el Microsoft SQL Server Management Studio Express, el cual es un entorno grfico para gestionar las bases de datos que vayamos creando, de la siguiente URL: http://www.microsoft.com/downloads/details.aspx?displaylang=es&FamilyID=c243a5a e-4bd1-4e3d-94b8-5a0f62bf7796#filelist Instalamos los dos paquetes de software....

Una vez instalado, nos vamos al Management Studio y creamos una base de datos, llamada imagenes, con una tabla, llamada registro.

Como podemos observar, se crea una tabla con tres campos, un int, un nvarchar y un tipo image.

Una vez tenemos instalado SQLServer 2005, con nuestra base de datos y nuestra tabla, vamos a instalarpyodbc, el software de Python para crear conexiones ODBC a orgenes de datos, en este caso, el software de Microsoft. Para ello, descargamos el pyodbc, desde http://code.google.com/p/pyodbc/. Creamos a continuacin, mediante las Herramientas Administrativas/Orgenes de datos (ODBC), nuestra conexin:

NOTA: El lector debe de tener en cuenta que existe un mdulo especfico para la conexin de SQLServercon Python, llamado pymssql, que se puede obtener de http://code.google.com/p/pymssql/. NOTA 2: Pudiera ser que con SQLServer 2005 Express Edition aparezcan ciertos errores a la hora de crear la conexin ODBC referidos a la configuracin del mismo, con el propsito de permitir conexiones remotas. Bien, la solucin la tenis aqu: http://support.microsoft.com/kb/914277/es. Una vez creado el ODBC y la conexin correctamente realizada, ya tenemos todo listo para programar enPython. El cdigo para crear una conexin desde Python a SQLServer 2005, mediante pyodbc, podra ser tal que as:

import pyodbc

# Cadena de conexin. cadenaConexion = 'DSN=imagenes;UID=ABUSIMBEL\familia'

try: conexionSQLServer = pyodbc.connect(cadenaConexion) cursorSQLServer = conexionSQLServer.cursor() print "Conectado con SQLServer 2005 Express!" except: print "No he podido conectar con base de datos SQLServer!" # Cerramos cursor y conexin. print "Cerrando conexiones!" cursorSQLServer.close() conexionSQLServer.close() Si todo ha ido bien, debe de aparecer algo como esto: Conectado con SQLServer 2005 Express! Cerrando conexiones! A continuacin vamos a insertar una imagen en la tabla registro de la base de datos imagenes. El cdigo podra ser tal que as: import os fichero_imagen = os.path.realpath('alvaro.jpg') imagen = open(fichero_imagen,'rb').read() Cargamos un fichero jpg, y lo referenciamos mediante imagen. Se supone que el fichero ha de existir. El cdigo para insertar una imagen en la base de datos es el siguiente: # Cadena SQL a ejecutar. cadenaSQL = "insert into registro values (1,'alvaro',?)" # Lanzamos Sentencia. cursorSQLServer.execute(cadenaSQL, (pyodbc.Binary(imagen),)) # Confirmamos escritura. conexionSQLServer.commit() Cabe destacar que transformamos en binario la imagen cargada del fichero. Adems hacemos commit, no olvidarlo. Si nos vamos al Management Studio y hacemos una consulta a la tabla tenemos la solucin:

Bien, ya sabemos como insertar imgenes en la base de datos. Ahora toca como recuperar la informacin, mediante el select correspondiente. El cdigo para hacer esto podra parecerse a lo siguiente: # Creamos el nombre de un fichero destino. fichero_destino = os.path.realpath('destino.jpg') # Lanzamos la consulta de seleccin SQL. imagen = cursorSQLServer.execute('SELECT * FROM registro WHERE id = 1') # Creamos un fichero de destino (temporal). fichero_final = open(fichero_destino,'wb') # Escribimos en el fichero y lo cerramos. fichero_final.write(imagen.next()[2]) fichero_final.close() Cabe destacar que se crea un fichero de salida temporal (destino.jpg) para obtener en disco el fichero seleccionado de la base de datos. Tambin decir que utilizamos next() para iterar sobre el cursor y obtener la imagen, que se encuentra en la posicin 3 de la tupla (es decir, imagen.next()[2]), ya que la tabla tiene 3 campos y el campo imagen es el tercero. Decir que si se quiere que se vea automticamente la imagen recuperada, se puede utilizar: fichero_destino = os.path.realpath('destino.jpg') os.startfile(fichero_destino) En mi sistema Windows, automticamente se abre el programa asociado a ficheros de imgenes, Visor de imgenes y faz de Windows, dando como resultado:

Imgenes serializadas en objetos con Python


Bien. Estamos en la segunda parte del post. Ahora lo que vamos a hacer es guardar una imagen dentro de un objeto y dicho objeto guardarlo en disco. Sera as como un wrapper de la imagen que se guardar en disco. Lo bueno que tiene esto es que se pueden guardar mltiples imgenes en cualquier tipo de contenedor (lista, tupla, diccionario) y guardarla directamente en disco, a capn. Para ello vamos a crear primero una clase, llamada persistencia, que tendr la funcionalidad de cargar y guardar un objeto. El cdigo que define la clase persistencia es el siguiente:

import cPickle

class persistencia(object): def nombre_clase(self): return str(self).split(' ')[0].split('.')[1]

def cargar(self, nombre_fichero = None): if nombre_fichero is None:

nombre_fichero = self.nombre_clase() manejador_fichero = open(nombre_fichero,'r') objeto = cPickle.load(manejador_fichero) manejador_fichero.close() return objeto

def salvar(self, objeto, nombre_fichero = None): if nombre_fichero is None: nombre_fichero = self.nombre_clase() # Fichero que contendr el objeto. manejador_fichero = open(nombre_fichero,'w') # Volcamos el objeto de memoria al fichero. cPickle.dump(self, manejador_fichero) # Cerramos fichero. manejador_fichero.close()

Ahora, nicamente hay que crear una clase que herede de persistencia, para obtener su funcionalidad, e implementar las estructuras necesarias para guardar imgenes. Para ello implementamos la clase registro, tal que as:

class registro(persistencia): def __init__(self): self._registro = []

def insertar_persona(self, nombre, foto): self._registro.append([nombre, foto])

def devolver_persona(self, nombre = None): if nombre is None: return self._registro else: for i in self._registro: if i[0] == nombre: return i return None Ahora falta, por fin, utilizar las clases que hemos diseado, para poder ver que efectivamente funciona la idea. El cdigo para serializar una imagen en un objeto podra tener el siguiente: import os # Cargamos imagen. fichero_imagen = os.path.realpath('alvaro.jpg')

imagen = open(fichero_imagen,'rb').read() # Instanciamos la clase que contendr el registro de personas. personas = registro() personas.insertar_persona('alvaro',imagen) personas.salvar(personas) Como podemos observar la funcionalidad heredada nos permite guardar la imagen en un fichero, mediante laserializacin del objeto. Decir que hemos incluido una imagen nicamente. Podramos incluir tantas imgenes como quisiramos. Evidentemente se crea un fichero, llamado registro, el cual tiene el siguiente contenido:

El formato del fichero nos da igual. Lo importante es que podamos recuperar la informacin guardada en las estructuras de datos de alto nivel que dispone Python. Vamos por ltimo a ver cmo recuperar la informacin guardada en el objeto serializado. Podramos utilizar un cdigo como este: import os # Obtenemos datos. personas = registro() personas = personas.cargar() individuo = personas.devolver_persona('alvaro') # Creamos fichero. fichero_destino = os.path.realpath('destino.jpg') imagen = open(fichero_destino,'wb') imagen.write(individuo[1]) imagen.close() # Y lo mostramos por pantalla, para ver que efectivamente funciona la idea. os.startfile(fichero_destino)

Esto es todo por el momento. Saludos.


en 21:00