[Fixed]-Django and Dropzone.js

9👍

I’m working with Dropzone and Django myself for creating Image objects for each file uploaded, which seems to be akin to what you want to do. I’d like to point out some things that I’ve experienced and show you how I’m doing it to see if that helps.

What you need

The things that you need in order to create a record in the Database for files uploaded with Dropzone is:

  1. The Dropzone HTML form
  2. The Javascript initialization of Dropzone.
  3. A Django View to handle the uploaded files.

I don’t understand what you’re doing with the Form (is it just validating?) but it seems to be unnecessary. You don’t need it (and don’t use it) to actually save the file.

Accessing the uploaded files

First lets talk about how to access the files in request.FILES. By setting uploadMultiple: true on your Dropzone configuration you condition Dropzone not to send dzfile but to send each file represented as dzfile[%d] (i.e. dzfile[0], dzfile[1], etc).

Even if that was not the case you’re using request.FILES like if it was a list (for f in request.FILES), but like you point out it’s actually a dict.

Here’s what Python shows when I print request.FILES:

<MultiValueDict: {u'dzfile[1]': [<InMemoryUploadedFile: image2.jpg (image/jpeg)>], u'dzfile[2]': [<InMemoryUploadedFile: image3.jpg (image/jpeg)>], u'dzfile[0]': [<InMemoryUploadedFile: image1.jpg (image/jpeg)>]}>

To access the actual files you need to get each key by it’s name.

files = [request.FILES.get('dzfile[%d]' % i)
     for i in range(0, len(request.FILES))]

NOW you have the file list you wanted. Simply iterate through it and create your objects however you want. I’m not sure on how your Models work so I’m going to approximate.

for f in files:
    # Create a ClientUpload object by setting its FK to client and
    # FileField to the file. Correct me if I deduced the models incorrectly
    client_upload = ClientUpload.objects.create(
        client=current_client,
        file_upload=f,
    )

That should be enough to create the objects that you want.

Dropzone Javascript

It seems that in the Click event listener you add to the submit button you have to add

e.preventDefault();
e.stopPropagation();

before calling processQueue() to avoid a double form submission.

As to the sendingmultiple, successmultiple and errormultiple, what do you want to happen there? The comments are just there to indicate when those events are trigered.

I personally use:

this.on('sendingmultiple', function () {
    // `sendingmultiple` to hide the submit button
    $('#my-dropzone').find('button[type=submit]').hide();
});
this.on('successmultiple', function (files, response) {
    // `successmultiple` to reload the page (and show the updated info)
    window.location.reload();
});
this.on('errormultiple', function (files, response) {
    // `errormultiple` to un-hide the button
    $('#my-dropzone').find('button[type=submit]').show();
});

But of course you can do what you want.

And finally, what do you intend to happen with that last line in the <script> tag? I don’t quite understand it, it looks like if you wanted to re-process the queue on success. It seems not to belong there.

Comment if anything’s off, but this setup works fine for me.

1👍

In your Javascript, I think you want to use this for the paramName:

paramName: "file_upload",

in order for a Django Form or ModelForm to recognize the uploaded files.

Also make sure that the upload request is using a multipart/form-data content type.

Also, try this instead of “get_list”:

dz_files = request.FILES.getlist("file_upload")

0👍

I don’t know if what i show now will help you specifically but maybe it will help others,Working with dropzone made me do a workaround because ajax, files and django combined are always a little complicated.

so in my html i have this code:

<div class="logos">
  <i class="fa fa-upload" id="dropzone_icon" data-name="icon" title="{% trans "Drag and drop or click" %}" alt="{% trans "Drag and drop or click" %}" ></i>
  <input type="hidden" name="icon" value="" >
  <input type="hidden" name="icon_name" value="" >
  <div class="img-holder">
    <img title='{% trans "Upload a Company Icon" %}' id="img_icon" alt='{% trans "Company icon" %}' src="{* icon *}"/>
  </div>
  <label>{% trans "Company Icon" %}</label>
</div>

in my js i got this:

dropz = new Dropzone(value, {
    url: "branding/dropzone",
    maxFiles: 1,
    acceptedFiles: "image/*",
    thumbnail: function(file, dataUrl) {
        /* change existing image */
        var file_type = file.name.split('.');
        file_type = file_type[file_type.length - 1];
        if(!(file_type=="png" || file_type=="jpg" || file_type=="jpeg")){
            createAlert('file type must be .png, .jpg or .jpeg', '#pp_content', 'alert');
            return false;
        }
        $("input[name='icon']").val(dataUrl.split(",")[1]);
        $("input[name='icon_name']").val(file.name);
        $("#img_" + type).prop("src", dataUrl);
        this.removeFile(file);
    },
    previewTemplate: "<span></span>",
    autoProcessQueue: false
});

this tells dropzone to insert into the values into the inputs(the base64 presentation of the image, and the file name) so basically i’m sending the image as a string.

after sending the inputs as a form in the ajax, this is how i handle them in my views.py:

import datetime
from django.core.files.base import ContentFile

def base64_to_image(img_b64,img_name):
"""
Creates image file from bas64 encoded data
:param img_b64: base64 data
:param img_name: filename for created image
:return: file or false if there's no data
"""
if img_b64:
    image_data = b64decode(img_b64)
    img_file = ContentFile(image_data,datetime.datetime.now().strftime("%y%d%m_%H%M%S") + img_name)
    return img_file
else:
    return False

company.icon = base64_to_image(request.POST["icon"], request.POST["icon_name"])
company.save()

this is my work around working with dropzone, maybe it will help others here as well

Leave a comment