Automágica: durante 2017 estoy trabajando bastante en Automágica, mi software para editar libros: Más información - Posts relacionados

Python: guardar imagenes en una base de datos Sqlite

Hace un par de días Walter de Nicaragua me consultaba:

Estoy trabajando en una aplicacion para niños en las xo´s , estoy usando sqlite3 para guardar la informacion, y tambien necesito guardar fotos dentro de la base de datos.

Como la fotos seran tomadas con la camara de las propias XO's, asumo no son tan grande en resolucion y tamaño.

Tambien, estuve revizando la lista de correo, pero no hay nada concreto, y a decir verdad recomiendan que guarde una referencia de la imagen en la base de datos, y luego haga una consulta, para recuperarla, pero tambien he visto que tiene sus pro y sus contras.

Esta es la respuesta. Primero necesitamos una tabla con un campo de tipo BLOB donde guardar la imagen:

>>> import sqlite3

>>> conn = sqlite3.connect('/tmp/example')

>>> c = conn.cursor()

>>> c.execute('''create table imagenes (imagen BLOB);''')

Abro una imagen que tengo en disco, mismo directorio que donde ejecute

el intérprete de Python, la cargo en memoria y la guardo en la base.

>>> imgdata = open('tomyNarnia.jpg', 'r').read()

>>> len(imgdata)

1613949

>>> buff = sqlite3.Binary(imgdata)

>>> c.execute('insert into imagenes values(?);', (buff,))

>>> conn.commit()

>>> conn.close()

Luego podemos cerrar el intérprete. Con sqlite3 importado, recuperamos

la imagen.

>>> conn = sqlite3.connect('/tmp/example')

>>> c = conn.cursor()

>>> a = c.execute('select imagen from imagenes')

>>> img = a.fetchone()

>>> len(img)

1

>>> img

(<read-write buffer ptr 0x1c75d60, size 1613949 at 0x1c75d20>,)

El resultado es una tupla, pero como seleccionamos un solo campo de la

tabla, hay un solo elemento.

>>> img = img[0]

>>> len(img)

1613949

Finalmente lo escribimos en una imagen.

>>> f = open('newimage.jpg', 'w')

>>> f.write(img)

>>> f.close()


3 features de SQLite que no conocía

SQLite es (o se debate entre si es o no) un motor de base de datos liviano. No requiere configuración, no usa un servidor, su código ocupa poco espacio y una base de datos ocupa un solo archivo. Tal vez por estas características es usado no solo en aplicaciones de escritorio y sitios web, sino también dentro de: el lenguaje de programación PHP, el navegador web Firefox y muchos dispositivos móviles (más). Hace unos días lo estoy usando para una aplicación Django mono-usuario. Hoy leyendo su página web, descubrí 4 características que no conocía, me llamaron la atención y me gustaron mucho.

La siguiente es una traducción libre de la página web de la herramienta.

El archivo de la base de datos se mantiene en distintas plataformas

El formato de archivo de SQLite es cross-platform. Un archivo de base de datos escrito en una máquina puede ser copiado a y usado en una máquina diferente con una arquitectura diferente. Big-endian o little-endian, 32-bit o 64-bit, no importa. Todas las máquinas usan el mismo formato de archivo. Más aún, los desarrolladores han mantenido el formato estabe y compatible hacia atrás, entonces versiones nuevas de SQLite pueden leer y escribir archivos de base de datos más viejos

La mayoría de los otros motores SQL requieren que bajes y restaures la base de datos al cambiar de una plataforma a otra y a menudo al actualizar a una nueva versión del software.

Tipado manifesto

La mayoría de los motores SQL usan tipado estático. Un tipo de dato es asociado con cada columna en una tabla y solo valores de ese tipo en particular se pueden guardar en esa columna. SQLite relaja esta restricción usando tipado manifiesto. En este tipo de tipado, el tipo de dato es una propiedad del valor en si mismo, no de la columna en el que el valor es almacenado. SQLite así permite que el usuario almacene cualquier valor de cualquier tipo de dato en una columna sin importar el tipo declarado de esa columna. (Hay algunas excepciones a esta regla: una columna de tipo INTEGER PRIMARY KEY solo almacenará enteros. Y SQLite intentará acomodar los valores al tipo de dato declarado en la columna cuando pueda).

Creemos que la especificación del lenguaje SQL permite el uso de tipado manifiesto. De todas formas, la mayoría de los otros motores SQL son estáticamente tipados y por eso algunas personas creen que el uso de tipado manifiesto es un bug en SQLite. Pero los autores de SQLite están convencidos de que esto es una característica valiosa. El uso de tipado manifiesto en SQLite es una decisión de diseño deliberada que ha probado en la práctica hacer que SQLite sea más confiable y fácil de usar, especialmente cuando se usa en combinación con lenguajes de programación dinámicamente tipados como Tcl y Python.

Registros de tamaño variable

La mayoría de los otros motores de base de datos SQL reservan una cantidad fija de espacio en disco por cada fila en la mayoría de las tablas. Hacen algunos trucos para manejar BLOBs y CLOBs que pueden tener un tamaño muy variable. Pero para la mayoría de las tablas, si declarás una columna de tipo VARCHAR(100), entonces el motor de base de datos reservará 100 bytes de espacio en disco sin importar cuanta información realmente guardes en esa columna.

SQLite, en contraste, usa dolo la cantidad de espacio en disco que realmente se necesita para almacenar la información en la fila. Si guardás un solo carácter en un columna de tipo VARCHAR(100), solo un byte de espacio en disco será consumido. (En realidad 2 bytes - hay cierta sobrecarga el principio de cada columna para guardar su tipo de dato y longitud).

El uso de registros de tamaño variable en SQLite tiene varias ventajas. Resulta en archivos de base de datos más pequeños, obviamente. También hace que la base de datos corra más rápido, ya que hay menos información que mover desde y hacia el disco. Y, el uso de registros de tamaño variable hace posible que SQLite use tipado manifiesto en lugar de tipado estático.

Más características

Una lista de todas las características de SQLite puede encontrarse en http://www.sqlite.org/different.html