Saving a decoded temporary image to Django Imagefield
Asked Answered
C

3

6

I'm trying to save images which have been passed to me as Base64 encoded text into a Django Imagefield.

But it seems to not be saving correctly. The database reports all my images are stored as "" when it should report them as a filename for example:

"template_images/template_folders/myImage.png"

The code that's trying to save my images is as follows:

elif model_field.get_internal_type() == "ImageField" or model_field.get_internal_type() == "FileField":  # Convert files from base64 back to a file.
    if field_elt.text is not None:
        setattr(instance, model_field.name, File(b64decode(field_elt.text)))
Cockalorum answered 27/2, 2013 at 15:20 Comment(0)
R
28

After reading this answer, I got this to work:

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

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

Therefore, I suggest you change your code to:

from django.core.files.base import ContentFile

# Your other code...

elif model_field.get_internal_type() == "ImageField" or model_field.get_internal_type() == "FileField":  # Convert files from base64 back to a file.
    if field_elt.text is not None:
        image_data = b64decode(field_elt.text)
        setattr(instance, model_field.name, ContentFile(image_data, 'myImage.png'))

Then, assuming your ImageField is defined with the upload_to argument set to template_images/template_folders/, you should see the file save down to YOUR_MEDIA_URL/template_images/template_folders/myImage.png

Rainbow answered 13/3, 2013 at 3:22 Comment(3)
I tried to follow the same approach, though I get 'Incorrect padding' on decode. Any suggestion?Parodist
Yup, you don't want to include the initial data:image/gif;base64, bit but then I guess you probably know that by now, just for the people that came here via Google like I did.Sugar
i think this one might fail because you dont need to include data:image/*;base64, part of the file.Vigilantism
S
2

Another good approach based on this SO answer: https://mcmap.net/q/275243/-django-rest-framework-upload-image-quot-the-submitted-data-was-not-a-file-quot tried it and tested in django 1.10

I made a function for decoded base64 file.

def decode_base64_file(data):

    def get_file_extension(file_name, decoded_file):
        import imghdr

        extension = imghdr.what(file_name, decoded_file)
        extension = "jpg" if extension == "jpeg" else extension

        return extension

    from django.core.files.base import ContentFile
    import base64
    import six
    import uuid

    # Check if this is a base64 string
    if isinstance(data, six.string_types):
        # Check if the base64 string is in the "data:" format
        if 'data:' in data and ';base64,' in data:
            # Break out the header from the base64 content
            header, data = data.split(';base64,')

        # Try to decode the file. Return validation error if it fails.
        try:
            decoded_file = base64.b64decode(data)
        except TypeError:
            TypeError('invalid_image')

        # Generate file name:
        file_name = str(uuid.uuid4())[:12] # 12 characters are more than enough.
        # Get the file name extension:
        file_extension = get_file_extension(file_name, decoded_file)

        complete_file_name = "%s.%s" % (file_name, file_extension, )

        return ContentFile(decoded_file, name=complete_file_name)

Then you can call the function

import decode_base64_file

p = Post(content='My Picture', image=decode_based64_file(your_base64_file))
p.save()
Salesclerk answered 20/4, 2017 at 1:17 Comment(0)
F
1

I guess this is the cleanest and shortest way to do this.

Here is how you can handle a Base64 encoded image file in a post request at the Django-based (drf also) API end which saves it as an ImageField.

Let say you have a Model as follows:

Class MyImageModel(models.Model):
      image = models.ImageField(upload_to = 'geo_entity_pic')
      data=model.CharField()

So the Corresponding Serializer would be as follows:

 from drf_extra_fields.fields import Base64ImageField

 Class MyImageModelSerializer(serializers.ModelSerializers):
      image=Base64ImageField()
      class meta:
         model=MyImageModel
         fields= ('data','image')
      def create(self, validated_data):
        image=validated_data.pop('image')
        data=validated_data.pop('data')
       return MyImageModel.objects.create(data=data,image=image)

The corresponding View can be as follows:

elif request.method == 'POST':
    serializer = MyImageModelSerializer(data=request.data)
    if serializer.is_valid():
        serializer.save()
        return Response(serializer.data, status=201)
    return Response(serializer.errors, status=400)

Notice In the Serializer I have used Implementation of Base64ImageField provided in the module django-extra-field

To install this module run the command

pip install pip install django-extra-fields

Import the same and Done!

Send (via post method) your image as an Base64 encoded String in JSON object along with any other data you have.

Fancher answered 9/3, 2017 at 14:25 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.