Python (2)


Upload files to Django Rest Framework using AngularJS

Encoding the image to “base64”, send it to our DRF endpoint and on our DRF serializers change the ImageField to Base64ImageField was the implementation I used:

On the client side, on my angular app:

angular.controller('ImageUploadFormCtrl', function($scope, Photo){
  $scope.submitForm = function(isValid){
    if(isValid){
      f = new FileReader(); // or $window.FileReader()
      
      f.onload = function () {
        $scope.formData.image = f.result; // This is a base64 string

        Photo.save({}, $scope.formData).$promise.then(function(data){
          // 200 Response
          alert('Client image successfully updated.');
        }, function(error){
          // 400 Response
          console.log('Error', error);
          alert('An error has ocurred.');
        })
      };      
      
      // Read the file selected on the field with ID "image-field"
      f.readAsDataURL(document.getElementById('image-field').files[0]);
    }
  }
});

On the server side on my Django app, specifically on the serializers.py file:

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

class Base64ImageField(serializers.ImageField):
  def to_internal_value(self, data):
    if isinstance(data, basestring) and data.startswith('data:'): # You can change "data:" to "data/image:"
      format, imgstr = data.split(';base64,')
      ext  = format.split('/')[-1]
      id   = uuid.uuid4()
      data = ContentFile(base64.b64decode(imgstr), name=id.urn[9:])

    return super(Base64ImageField, self).to_internal_value(data)

class PhotoSerializer(serializers.ModelSerializer):
  image = Base64ImageField(allow_empty_file=False)
  
  class Meta:
    fields           = ('id', 'image')
    model            = Photo
    read_only_fields = ('id', )

I found out that this is the cleaner way to do this. If you have another alternative, please share it.




Require activated virtualenv on PIP

I highly recommended to separate your working environments so every project has their own set of packages. To do this just edit the ~/.bash_profile file.

export PIP_REQUIRE_VIRTUALENV=true
# define a "global pip" function to use outside virtualenv:
gpip(){
    PIP_REQUIRE_VIRTUALENV="" pip "$@"
}

After that, reload the source file with this command source ~/.bash_profile.