Guardar archivo bs64 en Django FileField

We Are Cactus
Nov 13, 2015 · 2 min read

Al crear APIs para APPs, muchas veces los clientes móviles (o web) nos envían los archivos en formato base 64 como un string, y nosotros hemos de descodificarlo y almacenarlo como un archivo en Django. (Por ejemplo, para su posterior subida a Amazon S3).

Lo primero que necesitamos es importar lo siguiente:

from base64 import b64decode
from django.core.files.base import ContentFile

Con esto, tenemos capacidad para leer el string bs64, y para obtener el contenido del fichero (Una vez decodificado).

Para decodificar el string, dando por hecho que le string es una variable llamada “b64_text”:

image_data = b64decode(b64_text)

Ahora, obtenemos el contenido del archivo decodificado y lo asociamos al FileField, y guardamos el objeto:

my_model_instance.cool_image_field = ContentFile(image_data, 'whatup.png')
my_model_instance.save()

Ahora un ejemplo práctico. Por ejemplo para Django Rest Framework. Imaginad que tenemos un modelo llamado “Photography”, que tiene únicamente un campo llamado “description” y otro llamado “attachedFile”.

class Photography(models.Model):    attachedFile = models.FileField(
verbose_name="Photography File",
upload_to='photography_attached',
null=True,
blank=True
)
description = models.CharField(
verbose_name="Photography Description",
max_length=300,
null=True,
blank=True
)

Y nosotros queremos hacer un POST de esa entidad, y almacenar el archivo que venga en un FileField (independientemente de que no sea una imágen). Lo se, en este ejemplo, siendo “Photography”, deberían ser solo imágenes, pero bueno, echadle imaginación… ;-)

class DamageReportView(APIView):
def post(self, request, format=None):
received = request.data
newPhotography = Photography()
newPhotography.description = received['description']
img_received = received['attachedFile']
img_received_ext = img_received.split(';')
img_received_ext = img_received_ext[0].split(':')
img_received_ext = img_received_ext[1].split('/')
img_received_ext = img_received_ext[1]
clear_image_data = img_received.replace('data:image/jpeg;base64,','')
image_data = b64decode(clear_image_data)
newPhotography.attachedFile = ContentFile(image_data, uuid.uuid4()) + '.' + img_received_ext)
newPhotography.save()

Con esto, tendremos almacenada la imagen o archivo que pasemos. Puesto que recibimos un string, es muy facil parsearlo, por ejemplo para leer la extensión que recibimos. :D

Muchas veces, las apps, envían únicamente el contenido del fichero, sin el indicador de formato (por lo que este ejemplo n osirve para esos casos ,que obviarán la lectura de la extensión y siempre vendrá pre-asignada por el lado cliente.

Y esto es todo, es sencillo pero útil. Probablemente no sea la mejor solución, pero soy todo oídos si tenéis una mejor :D

PS: La info la obtuve en http://stackoverflow.com/questions/15115730/saving-a-decoded-temporary-image-to-django-imagefield , gracias al usuario dshap que a su vez se inspiró de la respuesta: http://stackoverflow.com/questions/3330677/a-stringio-like-class-that-extends-django-core-files-file/3332232#3332232 ;-)

Saludos!
Alberto.

Post original en: http://blog.algargar.com/2015/11/02/save-bs64-file-into-djanfo-filefield/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store