Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Saving a decoded temporary image to Django Imagefield

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)))
like image 956
Jharwood Avatar asked Feb 27 '13 15:02

Jharwood


3 Answers

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

like image 176
dshap Avatar answered Nov 22 '22 22:11

dshap


Another good approach based on this SO answer: https://stackoverflow.com/a/28036805/6143656 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()
like image 44
Roel Avatar answered Nov 22 '22 23:11

Roel


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.

like image 21
Nikhil Avatar answered Nov 23 '22 00:11

Nikhil