Guardar archivo bs64 en Django FileField
--
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/