javascriptpythonajaxdjangoajax-upload

Ajax call to Django function


I'm trying to delete a list of images selected via checkbox via Ajax, which have been uploaded via Django Ajax Uploader. I've successfully obtained a list of the images but I'm not sure how to pass it Django function via Ajax. Can anyone please advise on:

  1. How can I pass the list of selected images to a Django function to delete the images?
  2. How should I handle the CSRF for the ajax portion?

html

<!DOCTYPE html>{% load static from staticfiles %} {% load i18n %}
<html lang="en">

<head>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <title>Demo</title>
  <script src="{% static 'js/jquery.min.js' %}"></script>
  <!-- Latest compiled and minified JavaScript -->
  <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>

  <!-- Latest compiled and minified CSS -->
  <link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
  <!-- Optional theme -->
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/bootstrap-theme.min.css">
  <style>
    input.chk {
      margin-left: 70px;
    }
  </style>
</head>

<body>
  <div class="wrapper">
    <div id="content" class="clearfix container">
      {% load i18n crispy_forms_tags %}
      <form method="post" action="." enctype="multipart/form-data">
        {% csrf_token %} {% crispy form %} {% crispy formset formset.form.helper %}
        <div class="image-upload-widget">
          <div class="preview">
          </div>
          <div class="file-uploader">
            <noscript>
              <p>{% trans "Please enable JavaScript to use file uploader." %}</p>
            </noscript>
          </div>
          <p class="help_text" class="help-block">
            {% trans "Available file formats are JPG, GIF and PNG." %}
          </p>
          <div class="messages"></div>
        </div>
        <input type="submit" name="save" class="btn btn-primary pull-right" value="Submit">
        <input type="button" id="delete" class="btn btn-primary pull-left" value="Delete Selected Files">
      </form>
    </div>
  </div>
  <script src="{% static 'js/fileuploader.js' %}"></script>
  <link href="{% static 'css/fileuploader.css' %}" media="screen" rel="stylesheet" type="text/css" />
  <script>
    $(function() {
      var uploader = new qq.FileUploader({
        action: "{% url 'planner:ajax_uploader' %}",
        element: $('.file-uploader')[0],
        multiple: true,

        onComplete: function(id, fileName, responseJSON) {
          if (responseJSON.success) {
            url = '<label for="' + fileName + '"><img src="' + {{MEDIA_URL}} + responseJSON.url + '" alt="" /></label>';
            checkbox = '<p><input type="checkbox" class="chk" id="' + fileName + '" name="' + fileName + '" value="0" /></p>';
            $('.preview').append(url);
            $('.preview').append(checkbox);
          } else {
            alert("upload failed!");
          }
        },
        onAllComplete: function(uploads) {
          // uploads is an array of maps
          // the maps look like this: {file: FileObject, response: JSONServerResponse}
          alert("All complete!");

          alert(checkbox);
        },
        params: {
          'csrf_token': '{{ csrf_token }}',
          'csrf_name': 'csrfmiddlewaretoken',
          'csrf_xname': 'X-CSRFToken',
        },
      });
    });
  </script>
  <script>
    $("#delete").on('click', function() {
      var allVals = [];

      $(":checkbox").each(function() {
        var ischecked = $(this).is(":checked");
        if (ischecked) {
          allVals.push(this.id);
        }
      });
    });
  </script>
</body>

</html>


Solution

  • Once you got the list of images to delete, you pass it on to an Ajax call that will be handled by a Django view, like so:

    function submitData(data) {
        var csrftoken = getCookie('csrftoken'); // from https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#ajax 
        $.ajax({
            type: 'POST',
            beforeSend: function(xhr, settings) {
                if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                    xhr.setRequestHeader("X-CSRFToken", csrftoken);
                }
            },
            data: JSON.stringify(data),
            url: {% url 'image_handler' %}
        }).done(function(data) {
            console.log(data.deleted + ' images were deleted');
        }).error(function(data) {
            console.log('errors happened: ' + data);
        });
    }
    

    Then, in your views.py:

    def image_handler(request):
        if request.method != 'POST':
            return HttpResponseNotAllowed(['POST'])
    
        str_body = request.body.decode('utf-8')
        changes = json.loads(str_body)
        for change in changes:
            pass  # `change` contains the id of the image to delete
        data = {'status': 200,
                'deleted': len(changes)}
        return JsonResponse(data)
    

    It works pretty nicely :)