javascriptpythondjangodropzone.js

Dropzone.js does not post files in queue, only post files with JavaScript is incorrectly formatted


I have a Django project that uses Dropzone to upload multiple files to a project a user has created. All of this is within the same instance (project is created alongside file uploads), so I am using autoProcessQueue: false and running dropzone.processQueue() once the rest of the form data has been added.

I have a malformatted javascript file that ends up working. Files are posted and I can access them through <MultiValueDict: {'file': [<InMemoryUploadedFile: <img_name>.jpg (image/jpeg)>]}>. This 'works' but I cannot upload multiple files.

My correctly formatted javascript doesn't return anything. When I drop a file into the dropzone space in the html, the preview shows but now file is loaded. When I POST the form, I get this in the output for dropzone: <MultiValueDict:[]

Why is my bad JS partially functional, but my proper JS is not capturing any file uploads?

BAD but Working javascript.js for 1 file in dropzone

dropzonePreviewNode && (dropzonePreviewNode.id = "", previewTemplate = dropzonePreviewNode.parentNode.innerHTML, dropzonePreviewNode.parentNode.removeChild(dropzonePreviewNode), dropzone = new Dropzone(".dropzone", {
    headers: {
        'X-CSRFToken': csrftoken
    },
    autoProcessQueue: false,
    url: "create",
    method: "post",
    uploadMultiple: true,
    previewTemplate: previewTemplate,
    previewsContainer: "#dropzone-preview",
    acceptedFiles:'.jpg',
})
dropzone.on('success', dropzone.processQueue.bind(dropzone));

Correct JS, but not working - Causes Broken Pipe:

dropzonePreviewNode && (dropzonePreviewNode.id = "", previewTemplate = dropzonePreviewNode.parentNode.innerHTML, dropzonePreviewNode.parentNode.removeChild(dropzonePreviewNode), dropzone = new Dropzone(".dropzone", {
    headers: {
        'X-CSRFToken': csrftoken
    },
    autoProcessQueue: false,
    url: "create",
    method: "post",
    uploadMultiple: true,
    previewTemplate: previewTemplate,
    previewsContainer: "#dropzone-preview",
    acceptedFiles:'.jpg',
}));
dropzone.on('success', dropzone.processQueue.bind(dropzone));

html:

<form action="{% url 'apps:projects.create'%}" method="POST" enctype="multipart/form-data" class="dropzone">
        {% csrf_token %}
        {{ form.media }}
        {{ form.as_p }}
        ... (other form data input for project model) ...
    <div class="card">
        <div class="card-header">
            <h5 class="card-title mb-0">Attached files</h5>
        </div>
        <div class="card-body">
            <div>
                <p class="text-muted">Add Attached files here.</p>

                <div class="dropzone">
                    <div id="create-project" class="fallback">
                        <input name="file" type="file" multiple="multiple">
                    </div>
                    <div class="dz-message needsclick">
                        <div class="mb-3">
                            <i class="display-4 text-muted ri-upload-cloud-2-fill"></i>
                        </div>

                        <h5>Drop files here or click to upload.</h5>
                    </div>
                </div>

                <ul class="list-unstyled mb-0" id="dropzone-preview">
                    <li class="mt-2" id="dropzone-preview-list">
                        <!-- This is used as the file preview template -->
                        <div class="border rounded">
                            <div class="d-flex p-2">
                                <div class="flex-shrink-0 me-3">
                                    <div class="avatar-sm bg-light rounded">
                                        <img src="#" alt="Project-Image" data-dz-thumbnail class="img-fluid rounded d-block" />
                                    </div>
                                </div>
                                <div class="flex-grow-1">
                                    <div class="pt-1">
                                        <h5 class="fs-14 mb-1" data-dz-name>&nbsp;</h5>
                                        <p class="fs-13 text-muted mb-0" data-dz-size></p>
                                        <strong class="error text-danger" data-dz-errormessage></strong>
                                    </div>
                                </div>
                                <div class="flex-shrink-0 ms-3">
                                    <button data-dz-remove class="btn btn-sm btn-danger">Delete</button>
                                </div>
                            </div>
                        </div>
                    </li>
                </ul>
                <!-- end dropzon-preview -->
            </div>
        </div>
    </div>
    <!-- end card -->
    <div class="text-end mb-4">
        <button type="submit" class="btn btn-danger w-sm" onclick="location.href = '{% url 'apps:projects.list' %}';">Cancel</button>                                    
        <button type="submit" class="btn btn-success w-sm" id="add-btn">Create</button>
    </div>
</div>
</form>                                

view.py (Very simply, I just want to print the request.FILES at the moment to see if dropzone is working. Comfortable saving to the right location)

def apps_projects_create_view(request):
    if request.method == "POST":
        form = ProjectListAddForm(request.POST, request.FILES or None)
        if form.is_valid():
                form.save()
                print(form.cleaned_data)
                print(request.FILES)

models.py

class ProjectList(models.Model):
    identifier = models.AutoField(primary_key=True) 
    logo = models.ImageField(upload_to=project_directory_path, blank=True, null=True)
    name = models.CharField(max_length=50)
    client = models.ForeignKey('ClientCompany', blank=True, null=True, on_delete=models.CASCADE)   
    description = RichTextField(default="Please add Project description... ", blank=True)
    create_date = models.DateField(auto_now_add=True)
    end_date = models.DateField(blank=True, null=True)
    due_date = models.DateField(blank=True, null=True)
    assignment = models.ManyToManyField(TechnicianUser)        
    status = models.CharField(max_length=50,choices=PROJECT_STATUS)
    priority = models.CharField(max_length=10,choices=PRIORITY, null=True, blank=True)
    file = models.FileField(upload_to=project_directory_path, blank=True, null=True)
    tag = TaggableManager(blank=True)

Solution

  • This StackOverflow Answer by @jmur is what solved my issue:

    <script>
        Dropzone.autoDiscover = false;
        new Dropzone("#create-post",{
          clickable: ".dropzone",
          url: "{% url 'create_post' request.user.slug %}",
          previewsContainer: "#previewsContainer",
          paramName: "images",
          maxFiles: 10,
          maxFilesize: 30,
          acceptedFiles: '.png, .jpg, .jpeg',
          uploadMultiple: true,
          parallelUploads: 20,
          autoProcessQueue: false,
          init() {
            var myDropzone = this;
            this.element.querySelector("#submit-all").addEventListener("click", function(e){
              e.preventDefault();
              e.stopPropagation();
              myDropzone.processQueue();
            });
            this.on("success", function(file, response) {
                window.location.href=JSON.parse(file.xhr.response).url
            });
          }
        });
    </script>
    

    This is what needed to be changed / included in my script

    init() {
            var myDropzone = this;
            this.element.querySelector("#submit-all").addEventListener("click", function(e){
              e.preventDefault();
              e.stopPropagation();
              myDropzone.processQueue();
            });
            this.on("success", function(file, response) {
                window.location.href=JSON.parse(file.xhr.response).url
            });
          }