Image and File Uploads

New in 1.1 Drag and drop images or files into a form

This example shows how to upload an image or file to the server using AngularJS with Ajax.


     
    MyFormCtrl's scope:
    subscribe_data = {{ subscribe_data | json }}

    How does it work?

    If we want to upload an image or file to the server through an Ajax request, we have to divide the submission in two steps. This is because browsers can not serialize submitted file payload to JSON. Instead, we first must upload the image or file to the server encoded as multipart/form-data. The server then creates a temporary copy of the uploaded image or file and returns a reference to it. This temporary reference is stored inside a hidden field of our form.

    When the complete form is submitted by the client, only the reference to the temporary file is sent through Ajax. The server then moves the previously uploaded copy of that file into its MEDIA_ROOT directory and stores its location inside a model field.

    from djng.forms import fields, NgModelFormMixin, NgFormValidationMixin
    from djng.styling.bootstrap3.forms import Bootstrap3Form
    
    class SubscribeForm(NgModelFormMixin, NgFormValidationMixin, Bootstrap3Form):
        scope_prefix = 'subscribe_data'
        form_name = 'my_form'
        use_required_attribute = False
    
        full_name = fields.CharField(
            label='Full name',
            min_length=3,
            max_length=99)
    
        avatar = fields.ImageField(label='Photo of yourself')
    
        permit = fields.FileField(label='Your permit as PDF', accept='application/pdf')
    
        def clean_permit(self):
            """
            For instance, here you can move the temporary file stored in
            `self.cleaned_data['permit'].file` to a permanent location.
            """
            self.cleaned_data['permit'].file
    
    import json
    from django.http import HttpResponse
    from django.core.urlresolvers import reverse_lazy
    from django.utils.encoding import force_text
    from django.views.generic.edit import FormView
    
    class SubscribeView(FormView):
        template_name = 'image-file-upload.html'
        form_class = SubscribeForm
        success_url = reverse_lazy('form_data_valid')
    
        def post(self, request, **kwargs):
            if request.is_ajax():
                return self.ajax(request)
            return super(SubscribeView, self).post(request, **kwargs)
    
        def ajax(self, request):
            form = self.form_class(data=json.loads(request.body))
            response_data = {'errors': form.errors, 'success_url': force_text(self.success_url)}
            return HttpResponse(json.dumps(response_data), content_type="application/json")
    
    <script type="text/javascript">
        angular.module('djangular-demo', ['djng.forms']).config(function($httpProvider) {
            $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
            $httpProvider.defaults.headers.common['X-CSRFToken'] = '{{ csrf_token }}';
        });
    </script>
    
    <form name="{{ form.form_name }}" method="post" action="." validate ng-controller="MyFormCtrl">
        {% csrf_token %}
        {{ form.as_div }}
        <button type="submit" class="btn btn-primary">Submit via Post</button>
        <button type="button" ng-click="submit()" class="btn btn-primary">Submit via Ajax</button>
    </form>
    
    angular.module('djangular-demo').controller('MyFormCtrl', ['$scope', '$http', '$window', 'djangoForm',
                                                function($scope, $http, $window, djangoForm) {
    	$scope.submit = function() {
    		if ($scope.subscribe_data) {
    			$http.post(".", $scope.subscribe_data).then(function(response) {
    				if (!djangoForm.setErrors($scope.my_form, response.data.errors)) {
    					// on successful post, redirect onto success page
    					$window.location.href = response.data.success_url;
    				}
    			}, function() {
    				console.error('An error occured during submission');
    			});
    		}
    		return false;
    	};
    }]);
    
    from django.db import models
    from djng.forms import NgModelFormMixin, NgFormValidationMixin
    from djng.styling.bootstrap3.forms import Bootstrap3ModelForm
    
    class SubscribeUser(models.Model):
        full_name = models.CharField(
            "Full name",
            max_length=99)
    
        avatar = models.ImageField("Avatar", blank=False, null=True)
    
        permit = models.FileField("Permit", blank=True, null=True)
    
    class SubscribeForm(NgModelFormMixin, NgFormValidationMixin, Bootstrap3ModelForm):
        use_required_attribute = False
        scope_prefix = 'subscribe_data'
        form_name = 'my_form'
    
        class Meta:
            model = SubscribeUser
            fields = ['full_name', 'avatar', 'permit']
    

    A form accepting files and images without a permanent storage does not make much sense. Therefore you normally would create a Django model using an models.ImageField and/or models.FileField. From this model, you can create a form as usual. Image and file fields then are replaced by their AngularJS enabled counterparts, enabling drag & drop and immediate image preview.
    Some example code is shown in the last tab labeled Model.

    Fork me on GitHub