Image upload directive (angularJs and django rest framework)
Asked Answered
D

1

8

I need an image upload directive, here is how my code looks like:

# Model
class transporter(models.Model):
    company_name = models.CharField(max_length=100)
    address = models.CharField(max_length=100)
    image = models.FileField(upload_to=upload_path,blank=True, null=True)

    def upload_path(self, filename):
        return 'photos/%s/%s' % (self.company_name, filename)


# Serializer
class transporterSerializer (serializers.HyperlinkedModelSerializer):
    username = serializers.Field(source='username.username')

    class Meta:
        model = transporter
        fields = ('id','company_name','address','image')

it works with only django rest framework but i get Bad request error if I post the transporter model with angularjs. I need to upload the image and set the image field with the image URL. thank you

Danelledanete answered 16/2, 2014 at 17:43 Comment(1)
you may need to seperate this into two different api calls: one for the model, and one for the file upload. see also: #20474072Tableland
G
6

I'll share my experience with file upload using angular and drf.

Step 1:
Use a file model directive when binding your file input to an angular model. Im using the one below in several projects which does the trick for me. I got it from this blogpost by Jenny Louthan.

angular.module('appName').directive('fileModel', ['$parse', function ($parse) {
return {
    restrict: 'A',
    link: function(scope, element, attrs) {
        var model = $parse(attrs.fileModel);
        var modelSetter = model.assign;

        element.bind('change', function(){
            scope.$apply(function(){
                modelSetter(scope, element[0].files[0]);
            });
        });
    }
};
}]);

Used on a file input:

<form enctype="multipart/form-data">
    ...
    <input type="file" class="form-control" file-model="transporter.image">

Step 2:
Create a formData object in your controller or service which handles the post. This is can be done by first initiating a new formData object. Then looping through your angular object and setting all its attributes to that formData object.

If done in the controller this can be done like this:
(I'm using lodash for the _.each loop, but go with whatever suits you)

var fd = new FormData();
_.each($scope.transporter, function (val, key) {
    fd.append(key, data[key]);
});

Step 3:
Use angulars $http to post formData object to your url endpoint and handle the success request as you please!

$http({
    method: 'POST',
    url: '/api/url/to/endpoint',
    data: fd,
    transformRequest: angular.identity,
    headers: {
        'Content-Type': undefined
    }
}).success(function (response) {
    // Do stuff with you response
});
Gipon answered 12/3, 2015 at 20:3 Comment(2)
Under step 2, in your _.each() loop, you have an array called data. Where did this come from? When I try this loop I get an error saying data is undefined...Aer
@Aer the "data" here would be the original object. E.g in the above example the template binds an object "transporter" to the scope, the "data" in the controller would in this case refer to the "transporter" object.Gipon

© 2022 - 2024 — McMap. All rights reserved.