最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How do i include the csrf_token to dropzone Post request (Django) - Stack Overflow

programmeradmin1浏览0评论

Allright this is resolved. Just editing in case anyone runs into the same problem.

Add the Code posted in Comment marked as answer in the same javascript file. When defining

var myDropzone =  new Dropzone(...
  ...//More stuff here
  headers:{
    'X-CSRFToken' : csrftoken
  }

And thats it.

So im getting a 403 Forbidden when submitting the POST request through dropzone.js to django.Django displayed the message saying that I didnt include the CSRF token, but I don't know how to actually include it if im not using a form in the HTML.

document_form.html

{% extends 'base.html'  %}
{% load staticfiles %}
{% block title %}Add files{% endblock %}
{% block files %}
<div class="container-fluid" id="container-dropzone">
<div id="actions" class="row">

  <div class="col-lg-7">
    <span class="btn btn-success file-input-button">
      <i class="glyphicon glyphicon-plus"></i>
      <span>Add files...</span>
    </span>
    <button type="submit" class="btn btn-primary start">
      <i class="glyphicon glyphicon-upload"></i>
      <span>Start upload</span>
    </button>
    <button type="reset" class="btn btn-warning cancel">
      <i class="glyphicon glyphicon-ban-circle"></i>
      <span>Cancel upload</span>
    </button>
  </div>

  <div class="col-lg-5">
  <!-- file processing state -->
    <span class="fileupload-process">
      <div id="total-progress" class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
        <div class="progress-bar progress-bar-success" style="width:0%;" data-dz-uploadprogress></div>
      </div>
    </span>
  </div>
</div>

<div class="table table-striped files" id="previews">
  <div id="template" class="file-row">
    <div>
      <span class="preview"><img data-dz-thumbnail></span>
    </div>
    <div>
      <p class="name" data-dz-name></p>
      <strong class="error text-danger" data-dz-errormessage></strong>
    </div>
    <div>
      <p class="size" data-dz-size></p>
      <div class="progress progress-striped active" role="progressbar" aria-valuemin="0"
                 aria-valuemax="100" aria-valuenow="0">
        <div class="progress-bar progress-bar-success" style="width:0%" 
                    data-dz-uploadprogress>
        </div>           
      </div>
    </div>
    <div>
      <button class="btn btn-primary start">
        <i class="glyphicon glyphicon-upload"></i>
        <span>Start</span>
      </button>
      <button data-dz-remove class="btn btn-warning cancel">
        <i class="glyphicon glyphicon-ban-circle"></i>
        <span>Cancel</span>
      </button>
      <button data-dz-remove class="btn btn-danger delete">
        <i class="glyphicon glyphicon-trash"></i>
        <span>Delete</span>
      </button>
    </div>
  </div> <!-- /table-striped  -->
</div> <!-- /container-fluid  -->
</div>
{% endblock %}
{% block dz-add %}
  <script src="{% static 'js/dropzone-bootstrap.js' %}"></script>
{% endblock %}

dropzone-bootstrap.js

$(function() {
  var previewNode = document.querySelector("#template");
  previewNode.id = "";
  var previewTemplate = previewNode.parentNode.innerHTML;
  previewNode.parentNode.removeChild(previewNode);

  var myDropzone = new Dropzone(document.querySelector("#container-dropzone") , {
    url: "/dashby/files/add/", //url to make the request to.
    thumbnailWidth: 80,
    thumbnailHeight: 80,
    parallelUploads: 20,
    previewTemplate: previewTemplate,
    autoQueue: false,
    previewsContainer: "#previews",
    clickable: ".file-input-button",
    headers: { // Tried to apply the token this way but no success.
      'X-CSRFToken': $('meta[name="token"]').attr('content')
    }
  });

  myDropzone.on("addedfile", function(file){
    file.previewElement.querySelector(".start").onclick = function(){
      myDropzone.enqueueFile(file);
      };
  });

  myDropzone.on("totaluploadprogress", function(progress){
    document.querySelector("#total-progress .progress-bar").style.width = progress + "%";
  });

  myDropzone.on("sending", function(file){
    // Show total progress on start and disable START button.
    document.querySelector("#total-progress").style.opacity = "1";
    file.previewElement.querySelector(".start").setAttribute("disabled", "disabled");
  });

  // Hide progress bar when plete.
  myDropzone.on("queueplete", function(progress){
    document.querySelector("#total-progress").style.opacity = "0";
  });

  // Setup buttons for every file.
  document.querySelector("#actions .start").onclick = function(){
    myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED));
  };
  document.querySelector("#actions .cancel").onclick = function(){
    myDropzone.removeAllFiles(true);
  };
});

In my base.html im adding all the required files (dropzone, jquery, bootstrap and my custom javascript file)

For the django form handling:

views.py

class DocumentCreate(CreateView):
    model = Document
    fields = ['file']
    def form_valid(self, form):
        self.object = form.save()
        data = {'status': 'success'}
        response = JSONResponse(data, mimetype =
        response_mimetype(self.request))
        return response

My "Document" model

class Document(models.Model):
    file = models.FileField(upload_to = 'files/',
                                validators=[validate_file_type])
    uploaded_at = models.DateTimeField(auto_now_add = True)
    extension = models.CharField(max_length = 30, blank = True)
    thumbnail = models.ImageField(blank = True, null = True)

    def clean(self):
        self.file.seek(0)
        self.extension = self.file.name.split('/')[-1].split('.')[-1]
        if self.extension == 'xlsx' or self.extension == 'xls':
            self.thumbnail = 'xlsx.png'
        elif self.extension == 'pptx' or self.extension == 'ppt':
            self.thumbnail = 'pptx.png'
        elif self.extension == 'docx' or self.extension == 'doc':
            self.thumbnail = 'docx.png'

    def delete(self, *args, **kwargs):
        #delete file from /media/files
        self.file.delete(save = False)
        #call parent delete method.
        super().delete(*args, **kwargs)

    #Redirect to file list page.
    def get_absolute_url(self):
        return reverse('dashby-files:files')

    def __str__(self):
        #cut the 'files/'
        return self.file.name.split('/')[-1]

    class Meta():
        #order by upload_date descending
        #for bootstrap grid system. (start left side)
        ordering = ['-uploaded_at']

I created a Json response to handle the dropzone.

response.py

from django.http import HttpResponse
import json

MIMEANY = '*/*'
MIMEJSON = 'application/json'
MIMETEXT = 'text/plain'

# Integrating Dropzone.js with Django.
def response_mimetype(request):
    can_json = MIMEJSON in request.META['HTTP_ACCEPT']
    can_json |= MIMEANY in request.META['HTTP_ACCEPT']
    return MIMEJSON if can_json else MIMETEXT

# Custom HttpResponse
class JSONResponse(HttpResponse):
    def __init__(self, obj='', json_opts=None, mimetype=MIMEJSON,
                *args, **kwargs):
        json_opts = json_opts if isinstance(json_opts, dict) else {}
        content = json.dumps(obj, **json_opts)
        super(JSONResponse, self).__init__(content, mimetype,
                                          *args, **kwargs)

I've been stuck with this problem for a day now, so decided to ask for help here as I havn't been able to find one.

Thanks to anyone that takes the time to read and for any help/tips that I can get.

Allright this is resolved. Just editing in case anyone runs into the same problem.

Add the Code posted in Comment marked as answer in the same javascript file. When defining

var myDropzone =  new Dropzone(...
  ...//More stuff here
  headers:{
    'X-CSRFToken' : csrftoken
  }

And thats it.

So im getting a 403 Forbidden when submitting the POST request through dropzone.js to django.Django displayed the message saying that I didnt include the CSRF token, but I don't know how to actually include it if im not using a form in the HTML.

document_form.html

{% extends 'base.html'  %}
{% load staticfiles %}
{% block title %}Add files{% endblock %}
{% block files %}
<div class="container-fluid" id="container-dropzone">
<div id="actions" class="row">

  <div class="col-lg-7">
    <span class="btn btn-success file-input-button">
      <i class="glyphicon glyphicon-plus"></i>
      <span>Add files...</span>
    </span>
    <button type="submit" class="btn btn-primary start">
      <i class="glyphicon glyphicon-upload"></i>
      <span>Start upload</span>
    </button>
    <button type="reset" class="btn btn-warning cancel">
      <i class="glyphicon glyphicon-ban-circle"></i>
      <span>Cancel upload</span>
    </button>
  </div>

  <div class="col-lg-5">
  <!-- file processing state -->
    <span class="fileupload-process">
      <div id="total-progress" class="progress progress-striped active" role="progressbar" aria-valuemin="0" aria-valuemax="100" aria-valuenow="0">
        <div class="progress-bar progress-bar-success" style="width:0%;" data-dz-uploadprogress></div>
      </div>
    </span>
  </div>
</div>

<div class="table table-striped files" id="previews">
  <div id="template" class="file-row">
    <div>
      <span class="preview"><img data-dz-thumbnail></span>
    </div>
    <div>
      <p class="name" data-dz-name></p>
      <strong class="error text-danger" data-dz-errormessage></strong>
    </div>
    <div>
      <p class="size" data-dz-size></p>
      <div class="progress progress-striped active" role="progressbar" aria-valuemin="0"
                 aria-valuemax="100" aria-valuenow="0">
        <div class="progress-bar progress-bar-success" style="width:0%" 
                    data-dz-uploadprogress>
        </div>           
      </div>
    </div>
    <div>
      <button class="btn btn-primary start">
        <i class="glyphicon glyphicon-upload"></i>
        <span>Start</span>
      </button>
      <button data-dz-remove class="btn btn-warning cancel">
        <i class="glyphicon glyphicon-ban-circle"></i>
        <span>Cancel</span>
      </button>
      <button data-dz-remove class="btn btn-danger delete">
        <i class="glyphicon glyphicon-trash"></i>
        <span>Delete</span>
      </button>
    </div>
  </div> <!-- /table-striped  -->
</div> <!-- /container-fluid  -->
</div>
{% endblock %}
{% block dz-add %}
  <script src="{% static 'js/dropzone-bootstrap.js' %}"></script>
{% endblock %}

dropzone-bootstrap.js

$(function() {
  var previewNode = document.querySelector("#template");
  previewNode.id = "";
  var previewTemplate = previewNode.parentNode.innerHTML;
  previewNode.parentNode.removeChild(previewNode);

  var myDropzone = new Dropzone(document.querySelector("#container-dropzone") , {
    url: "/dashby/files/add/", //url to make the request to.
    thumbnailWidth: 80,
    thumbnailHeight: 80,
    parallelUploads: 20,
    previewTemplate: previewTemplate,
    autoQueue: false,
    previewsContainer: "#previews",
    clickable: ".file-input-button",
    headers: { // Tried to apply the token this way but no success.
      'X-CSRFToken': $('meta[name="token"]').attr('content')
    }
  });

  myDropzone.on("addedfile", function(file){
    file.previewElement.querySelector(".start").onclick = function(){
      myDropzone.enqueueFile(file);
      };
  });

  myDropzone.on("totaluploadprogress", function(progress){
    document.querySelector("#total-progress .progress-bar").style.width = progress + "%";
  });

  myDropzone.on("sending", function(file){
    // Show total progress on start and disable START button.
    document.querySelector("#total-progress").style.opacity = "1";
    file.previewElement.querySelector(".start").setAttribute("disabled", "disabled");
  });

  // Hide progress bar when plete.
  myDropzone.on("queueplete", function(progress){
    document.querySelector("#total-progress").style.opacity = "0";
  });

  // Setup buttons for every file.
  document.querySelector("#actions .start").onclick = function(){
    myDropzone.enqueueFiles(myDropzone.getFilesWithStatus(Dropzone.ADDED));
  };
  document.querySelector("#actions .cancel").onclick = function(){
    myDropzone.removeAllFiles(true);
  };
});

In my base.html im adding all the required files (dropzone, jquery, bootstrap and my custom javascript file)

For the django form handling:

views.py

class DocumentCreate(CreateView):
    model = Document
    fields = ['file']
    def form_valid(self, form):
        self.object = form.save()
        data = {'status': 'success'}
        response = JSONResponse(data, mimetype =
        response_mimetype(self.request))
        return response

My "Document" model

class Document(models.Model):
    file = models.FileField(upload_to = 'files/',
                                validators=[validate_file_type])
    uploaded_at = models.DateTimeField(auto_now_add = True)
    extension = models.CharField(max_length = 30, blank = True)
    thumbnail = models.ImageField(blank = True, null = True)

    def clean(self):
        self.file.seek(0)
        self.extension = self.file.name.split('/')[-1].split('.')[-1]
        if self.extension == 'xlsx' or self.extension == 'xls':
            self.thumbnail = 'xlsx.png'
        elif self.extension == 'pptx' or self.extension == 'ppt':
            self.thumbnail = 'pptx.png'
        elif self.extension == 'docx' or self.extension == 'doc':
            self.thumbnail = 'docx.png'

    def delete(self, *args, **kwargs):
        #delete file from /media/files
        self.file.delete(save = False)
        #call parent delete method.
        super().delete(*args, **kwargs)

    #Redirect to file list page.
    def get_absolute_url(self):
        return reverse('dashby-files:files')

    def __str__(self):
        #cut the 'files/'
        return self.file.name.split('/')[-1]

    class Meta():
        #order by upload_date descending
        #for bootstrap grid system. (start left side)
        ordering = ['-uploaded_at']

I created a Json response to handle the dropzone.

response.py

from django.http import HttpResponse
import json

MIMEANY = '*/*'
MIMEJSON = 'application/json'
MIMETEXT = 'text/plain'

# Integrating Dropzone.js with Django.
def response_mimetype(request):
    can_json = MIMEJSON in request.META['HTTP_ACCEPT']
    can_json |= MIMEANY in request.META['HTTP_ACCEPT']
    return MIMEJSON if can_json else MIMETEXT

# Custom HttpResponse
class JSONResponse(HttpResponse):
    def __init__(self, obj='', json_opts=None, mimetype=MIMEJSON,
                *args, **kwargs):
        json_opts = json_opts if isinstance(json_opts, dict) else {}
        content = json.dumps(obj, **json_opts)
        super(JSONResponse, self).__init__(content, mimetype,
                                          *args, **kwargs)

I've been stuck with this problem for a day now, so decided to ask for help here as I havn't been able to find one.

Thanks to anyone that takes the time to read and for any help/tips that I can get.

Share Improve this question edited Sep 29, 2016 at 17:40 Piero Marini asked Sep 29, 2016 at 17:04 Piero MariniPiero Marini 1311 silver badge11 bronze badges
Add a ment  | 

5 Answers 5

Reset to default 3

I have just figured this out, all you need to do is add this to your dropzone config:

headers: {'X-CSRFToken': '{{ csrf_token }}'},

good luck!

just place {% csrf_token %} anywhere in your Html file . it's automatically add

 <input type="hidden" name="csrfmiddlewaretoken" value="**************" />

Before sending data to the server just add extra field csrf_token which value is $("input[name='csrfmiddlewaretoken']").val();

Django’s docs have a reference for this:

While [a special parameter] can be used for AJAX POST requests, it has some inconveniences: you have to remember to pass the CSRF token in as POST data with every POST request. For this reason, there is an alternative method: on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token. This is often easier, because many JavaScript frameworks provide hooks that allow headers to be set on every request.
[…]

Acquiring the token is straightforward:

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

[…] Finally, you’ll have to actually set the header on your AJAX request, while protecting the CSRF token from being sent to other domains using settings.crossDomain in jQuery 1.5.1 and newer:

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

If you run these two code blocks before you start to make requests, it should Just Work™.

In summary, just use this code block:

// from https://docs.djangoproject./en/1.10/ref/csrf/ via http://stackoverflow./a/39776325/5244995.
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

The docs remend getting the CSRF token from the cookie, not the DOM. Try that.

While this is an old thread, I thought I'd share the solution that worked for me.

var myDropzone = $("#file-upload").dropzone({
        url: "/dashboard/api/v1/upload/",
        // addRemoveLinks : true,
        maxFilesize: 5,
        dictResponseError: 'Error uploading file!',
        headers: {'X-CSRFToken': window.CSRF_TOKEN},
        success: (file, response) => {
            console.log(JSON.parse(file.xhr.response));
        }
    });
发布评论

评论列表(0)

  1. 暂无评论