8

Here is my javascript code that works fine. but I like to keep javascript files seperate and not use as inline script tags

<script>
    $('.book').click(function() {
         var id= $(this).attr('id');
         data={
              'id':id,
              'csrfmiddlewaretoken':'{{ csrf_token }}',
              };
          $.ajax({
            url: '/post/book/',
            cache:'false',
            dataType:'json',
            type:'POST',
            data:data,
            success: function(data){
               //do something
              else {
                  //do something
              }
            }, 
            error: function(error){
              alert('error; '+ eval(error));
            }
          });
          return false;
      });
     });
</script>

I want to include this in my custom.js file that I have included in my base.html. which is

{% load static from staticfiles %}
{% load bootstrap3 %}
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>{% block title %}{% endblock %}</title>
  {% bootstrap_css %}
  <!-- Optional theme -->
  <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap-theme.min.css">
  <link href="{% static "css/custom.css" %}" rel="stylesheet">
  <!-- Latest compiled and minified JavaScript -->
  <script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
  <script src="http://ajax.aspnetcdn.com/ajax/jquery.dataTables/1.9.4/jquery.dataTables.js"></script>
  <script src="{% static "js/custom.js" %}" ></script>
  <script src="{% static "js/jquery.blockUI.js" %}"></script>
  {% bootstrap_javascript %}
  {% load bootstrap3 %}
{% load static from staticfiles %}
{% block content %} {% endblock %}

I am not able to reference csrf_token that is available in the current template in Django to the static js file. how can I get this to work?

brain storm
  • 30,124
  • 69
  • 225
  • 393

8 Answers8

27

If you want to reference template tags then you need that file to be templated (rendered) by Django. And I wouldn't recommend rendering all your static files via django...

You can either put the csrf_token in a global variable that you then access from your script. Something like this in your base.html:

<script>
    var csrftoken = '{{ csrf_token }}';
</script>

Or you can pull the csrftoken from the cookies in your javascript file. See this question for a solution for that. The cookie is called csrftoken. You can view it by opening up your dev tools and looking at the cookies for your domain.

Community
  • 1
  • 1
aychedee
  • 24,871
  • 8
  • 79
  • 83
10

You can either access the CSRF token from 'csrftoken' cookie at the client using following function:

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 = cookies[i].trim();
            // 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;
}

And calling it like:

getCookie('csrftoken');

Or you may simply define a variable in HTML template and use that in your client side script.

<script>
    var CSRF_TOKEN = '{{ csrf_token }}';
</script>
Debanshu Kundu
  • 785
  • 7
  • 18
3

The CSRF Token is available as a cookie on the page with the name "csrftoken". The Django docs suggest getting the cookie and passing it in the HTTP request headers as X-CSRFToken. Then you can protect the view using the @csrf_protect decorator.

Here are the Django docs on AJAX: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax.

So using the jQuery cookie plugin, your code might look like:

$.ajax({
  url: '/post/book/',
  cache: 'false',
  dataType: 'json',
  type: 'POST',
  data: data,
  beforeSend: function(xhr) {
    xhr.setRequestHeader('X-CSRFToken', $.cookie('csrftoken')),
  },
  success: function(data) {},
  error: function(error) {}
});
danasilver
  • 556
  • 3
  • 10
2

In Django 2.x Reference: https://docs.djangoproject.com/en/2.2/ref/csrf/

Here is a minimum example.

Fisrt insert your url in html template.

<input type="hidden" id="u_calc" data-url="{% url 'demo:calc' %}"/>

Then, get your url and csrf token from cookie. Use beforeSend in ajax request.

let u_calc = $("#u_calc").attr("data-url");

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 = cookies[i].trim();
            // 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));
}
function get_result(number) {
    let n = number.val();
    $.ajax({
        beforeSend: function (xhr, settings) {
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        },
        method: "POST",
        type: "POST",
        url: u_calc,
        async: true,
        dataType: "json",
        data: JSON.stringify({'number': n}),
        contentType: "application/json",
        success: function (data) {
            alert(data.result);
        },
    });
}

In views.py, the calc function may look like

def calc(request):
    if request.is_ajax() and request.method == "POST":
        data = json.loads(request.body)
        number = int(data["number"])
        return JsonResponse({"result": 2 * number})
counter2015
  • 869
  • 7
  • 18
2

You can just simply define it in the HTML template like:

<script>
var CSRF_TOKEN = '{{ csrf_token }}';
</script>

It will work

1

You can pass csrf_token like this

function deleteAccount(id, name) {
  if (confirm('Do you want to delete ' + name + '?')) {
    $.ajax({
      type: 'post',
      url: url,
      data: 'csrfmiddlewaretoken={{csrf_token}}',
      success: function() {
         window.location.reload(true);
      }
    });
  }
}
lifez
  • 318
  • 1
  • 4
  • 9
1
<button id="check_button" data-csrf="{{ csrf_token }}">
    button
</button>
$(document).ready(function() {
    $('#check_button').click(async function() {
        await fetch(url, {
            method: 'POST',
            headers: {
                'X-CSRFToken': $(this).data().csrf,
            },
            ...
        })
        ...
    })
})
-1

I've tried many ways to solve it and here's recap:

  1. Using {{ csrf_token }} in a seperate js file doesn't work event you embed it into django template.

  2. Using @csrf_protect in your view doesn't works as well because it can only protect a part of function.

  3. The right way to implement is here:

    from django.views.decorators.csrf import csrf_exempt

Then before the view function, using @csrf_exempt: Here is an example

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt

def function_name(request):

Your function here.

Hope it help

Community
  • 1
  • 1
  • 1
    This isn't solving the problem - it's avoiding the problem by turning off a security feature. It's like saying "to fix a broken doorbell, remove the door from your house so that people don't need to use the doorbell any more". – gasman Jun 11 '20 at 14:36