10

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?

11 Answers 11

31

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.

Sign up to request clarification or add additional context in comments.

Comments

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>

Comments

4

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

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

It will work

Comments

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) {}
});

2 Comments

why is @csrf_protect decorator necessary?
You shouldn't need it if you're using the CSRF Middleware. docs.djangoproject.com/en/dev/ref/contrib/csrf
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})

Comments

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);
      }
    });
  }
}

Comments

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,
            },
            ...
        })
        ...
    })
})

Comments

0

It is generally recommended that data should be passed using HTML data- attributes, or the json_script filter, rather than in embedded JavaScript. Reference

I recommend using the built-in template tag csrf_token passing in the filter json_script and then grabbing the token from Javascript.

{{ csrf_token|json_script:"csrf_token" }}
...
<script>
const csrf_token = JSON.parse(document.querySelector('#csrf_token').textContent);
</script>

Problem is that the token is not formatted as a string. You would need to convert the token to a string. I would just create a custom filter, named stringify which you would pipe to stringify the token

from django import template

register = template.Library()

@register.filter
def stringify(value):
    return str(value)

Such that,

{{ csrf_token|stringify|json_script:"csrf_token" }}

Then you can access the value in Javascript, and pass it in as a header for the AJAX request, or use it for something else.

Comments

0

You can use this: let csrf_token = document.getElementsByName('csrfmiddlewaretoken')[0].value; in Javascript.

Comments

0

Since none of the answers worked for me, here's how I ended up doing it.

$.ajax({
    url: "{% url 'my_ajax_url' %}",
    type: "POST",
    dataType: "json",
    headers: {'X-CSRFToken': "{{ csrf_token }}"},
    data: {'my_variable': my_variable},
    success: function (data) {
        // Do something
    },
    error: function(){
        // Log some error
    },
    timeout: 4000
});

With {{ csrf_token }} as part of the headers, we don't need any special tricks and can use a simple Function Based View to return the JSON:

def my_ajax_function(request):

    my_variable = request.POST['my_variable']
    
    # Do something with the variable, e.g. do a DB lookup
    my_object = MyObject.objects.filter(name=my_variable)

    if my_object:
        context = {
            "message_code": "OK",
            "message": "We received an object",
        }
    else:
        context = {
            "message_code": "ERROR",
            "message": "Something went wrong",
        }

    data = json.dumps(context)
    return HttpResponse(data, content_type='application/json')

Comments

-2

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

1 Comment

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".

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.