24

I need to receive an image from an app, and the best way I can think of is to send it into a JSON array encoded in Base64. The image is very small so I don't care about the extra overhead.

I have a model :

class Observation(models.Model):    
    ...
    sonogram_image = models.ImageField(upload_to=sonogram_dir)

And its serialiser:

class ObsvSerializerNoDetect(serializers.HyperlinkedModelSerializer):

    class Meta:
        model = Observation

Where should I put the code to decode the image?

gozzilli
  • 8,089
  • 11
  • 56
  • 87
  • Yes and no. I store the image as text and then rendering it to a web page is pretty easy, in the `img` tag you put `src="data:image/png;base64,"`. I'm not sure it's the best way but it works fine and is easy to implement. – gozzilli Sep 03 '13 at 15:41
  • @gozzilli could you provide snippest with view/serializer/models of your base64-based solution? – andilabs Jul 22 '14 at 22:41
  • My answer here may help you: http://stackoverflow.com/questions/25027093/django-rest-serialize-a-text-or-image-file-to-post-via-http-in-json/26405078#26405078 – xxx Oct 26 '14 at 21:17

4 Answers4

26

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() # From DRF Extra Fields
      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 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.

Daniel Benedykt
  • 6,496
  • 12
  • 51
  • 73
Nikhil
  • 1,021
  • 12
  • 13
  • 1
    Note that `django-extra-fields` is deprecated! Use [drf-extra-fields](https://github.com/Hipo/drf-extra-fields) instead – Genarito May 11 '22 at 19:11
2

There could be two best locations, depending on your use-case:

  1. in your serializer you have the validate_X and transform_X methods you can override for your field (see the validation docs) and to the conversion in both directions here.

  2. write your own custom field if you need the feature more often. You only have to define how the conversions run in both directions in to_native and from_native. Perhaps extend the original DRF ImageField to keep the image-data validation with PIL.

Update DRF3:

transform_X methods replaced by to_representation(). See removal-of-transform_field_name and Overriding serialization and deserialization behavior .

Also have a look at this DRF Base64ImageFieldMixin example.

Paolo
  • 20,112
  • 21
  • 72
  • 113
Denis Cornehl
  • 4,104
  • 1
  • 20
  • 24
2

Try django extra fields. Use Base64ImageField as a serializer field assuming of course you used an ImageField in your models.

phoenix
  • 7,988
  • 6
  • 39
  • 45
CuriousGeorge
  • 471
  • 3
  • 6
0

You can add this field type in your serializer

class YourModelSerilizer(serializers.Serializer):
    image_field = Base64ImageField()

Here is the proper guideline