El Blog de Trespams

Blog personal sobre tecnologia, gestió de projectes i coses que se me passen pel cap

Carregant imatges

Normalment quan treballam amb imatges amb Django ho feim des del punt de vista de disseny, és a dir, posam les imatges al directori on s'han de servir i per avall. Potser a vegades hem fer servir quelcom com el Django Photologue per a tenir les fotografies més estructurades dins la nostra aplicació.

Què passa però, si el que volem és carregar les fotografies des d'un script a la nostra base de dades, o quan ens trobam que la informació no ve pels canals habituals d'una imatge que es puja mitjançant un formulari.

Aquest és el cas que tractarem en aquest apunt. Tenim una imatge que ens arriba codificada en base64 i el que volem és afegir-la amb un petit comentari a la nostra aplicació.

El model que farem servir és tan senzill com això:

from django.db import models


class Photo(models.Model):
image = models.ImageField(upload_to='photos')
comments = models.TextField()

La imatge ens ha arribat com a una cadena de text. El contingut ho podeu trobar al subversion del projecte appfusedjango.

El primer que hem de fer es decodificar la imatge, després crearem una instància de la classe Photo, li assignarem el contingut, el comentari i guardarem. Fins aquí supòs que tothom d'acord.

El problema, però, és que ImageField suposa que li passarem una objecte del tipus File i nosaltres el que tenim és una cadena de text. Necessitarem per tant simular aquest tipus de dada de manera que puguem tractar amb informació que no vengui directament d'un fitxer de text. Ni més ni manco el ContentFile. Aquesta classe que podem trobar a django.core.files.base el que fa és precisament això.

Una altra de les coses que hem de fer és guardar la imatge i assignar-li el nom. Per fer això haurem de crear el nostre objecte Photo, guardar la imatge i després guardar-ho tot a la base de dades.

Anem a veure com quedaria:

import base64
from django.core.files.base import ContentFile
from sample.models import Photo

# ja tenim tot el necessari
raw_data = base64.b64decode(open('test/encoded_logo.b64').read())
# acabam de llegir les dades, podrien arribar directament
foto = Photo()
foto.image.save('the-image-name.gif', ContentFile(raw_data))
foto.comments = "Django & Python rules!"
foto.save()

El pas del 'image.save' és necessari perquè Django no guarda les imatges per defecte dins la base de dades sinó al sistema de fitxer (de fet podem guardar-ho allà on ens vengui de gust gràcies a les possibilitats del custom storage) així que necessitam definir tant el nom de la imatge com les dades. A la definició del camp ImageField ja li hem dit que voliem deixar les imatges a la carpeta photos que estarà dins el directori que tinguem definit com el nostre MEDIA_ROOT.

El projecte que he pujat serveix per demostrar la idea. Per provar-ho basta fer un

$ python manage.py shell

des del directori del projecte imatges per a convèncer-vos que la cosa funciona veient com es van creant les imatges dins la carpeta media/photos/ del projecte.

blog comments powered by Disqus