Search code examples
djangodjango-viewsdropzone.jsdjango-file-upload

Trying to use django and dropzone/


I'm trying to use dropzone.js with django.

I'm following the somewhat dated guide here (https://amatellanes.wordpress.com/2013/11/05/dropzonejs-django-how-to-build-a-file-upload-form/)

I strongly suspect My view is at issue.

def test(request):
    print "test view has been called"
    if request.method == 'POST':
        print "test request method is POST"
        form = UploadFileForm(request.POST, request.FILES)
        print request
        print request.FILES
        if form.is_valid():
            new_file = AttachedFiles(attachedfile=request.FILES['file'])
            new_file.save()
            id = new_file.pk
            print id
            print "test form valid"
            return HttpResponse(json.dumps({'id': id}), content_type="application/json")
       print "test form not valid"
   else:
       form = UploadFileForm()
   data = {'form': form}
   return render_to_response('mediamanager/test.html', data, context_instance=RequestContext(request))

I've tested submitting to it with the dropzone code

        <!-- IMPORTANT enctype attribute! -->
    <form id="my_dropzone" class="dropzone" action="/mediamanager/test/" method="post" enctype="multipart/form-data">
        {% csrf_token %}
     <button id="submit-all">
        Submit all files
    </button>
    </form>
    <script src="{% static 'dropzone/js/dropzone.js' %}"></script>
    <script type="text/javascript">
        Dropzone.options.myDropzone = {

            // Prevents Dropzone from uploading dropped files immediately
            autoProcessQueue : true,

            init : function() {
                var submitButton = document.querySelector("#submit-all")
                myDropzone = this;

                submitButton.addEventListener("click", function() {
                    myDropzone.processQueue();
                    // Tell Dropzone to process all queued files.
                });

                // You might want to show the submit button only when
                // files are dropped here:
                this.on("addedfile", function() {
                    // Show submit button here and/or inform user to click it.
                    console.log("blah")
                });
            }
        };
    </script>

and a basic form

<form action="{% url "test" %}" method="post" enctype="multipart/form-data">
  {% csrf_token %}
<input type="file" name="file" />
<input type="submit" value="Submit">
</form>

And the form is never valid. I'm using a modelform as suggested

class UploadFileForm(forms.ModelForm):
    class Meta:
        model = AttachedFiles

Solution

  • You can handle Dropzone posts like any other multipart form post.

    Here's how I proceed:

    @login_required
    @usertype_required
    def upload_picture(request, uid=None):
        """
        Photo upload / dropzone handler
        :param request:
        :param uid: Optional picture UID when re-uploading a file.
        :return:
        """
        form = PhotoUploadForm(request.POST, request.FILES or None)
        if form.is_valid():
            pic = request.FILES['file']
            # [...] Process whatever you do with that file there. I resize it, create thumbnails, etc.
            # Get an instance of picture model (defined below) 
            picture = ...         
            picture.file = pic
            picture.save()
            return HttpResponse('Image upload succeeded.')
        return HttpResponseBadRequest("Image upload form not valid.")
    

    The form is dead simple

    class PhotoUploadForm(forms.Form):
        # Keep name to 'file' because that's what Dropzone is using
        file = forms.ImageField(required=True)
    

    In your model you need the upload_to set:

    class Picture(models.Model):
        [...]
        # Original
        file = models.ImageField(upload_to=get_upload_path)
    

    And here's my upload path builder, but you can put anything

    def get_upload_path(instance, filename):
        """ creates unique-Path & filename for upload """
        ext = filename.split('.')[-1]
        filename = "%s.%s" % (instance.p_uid, ext)
        d = datetime.date.today()
        username = instance.author.username
    
        #Create the directory structure
        return os.path.join(
            'userpics', username, d.strftime('%Y'), d.strftime('%m'), filename
        )
    

    Don't forget the csrf_token in the html form itself (I'm using an angularJS directive on top of it so will be different for you)

    <form action="{% url 'upload_picture' %}" class="dropzone" drop-zone>
        {% csrf_token %}
        <div class="fallback">
            <h3>Your browser is not supported.</h3>
            <strong>
                <a href="https://browser-update.org/update.html" target="_blank">Click here for instructions on how to update it.</a>
            </strong>
            <p>You can still try to upload your pictures through this form: </p>
            <p>
                <input name="file" type="file" multiple />
                <input type="submit" value="Upload" />
            </p>
         </div>
     </form>