2

I'm working my way through 'Django 1.0 Web Site Development' and encountered a problem when using forms. The server complained about something concerning 'csrf'. I could solve it by adding {% csrf_token %} right after the form-tag. I already read the documentation at djangoproject.com but I have to admit that I don't fully understand what exactly is happening here. I don't use the middleware classes.

The real problem started when I got to ajax. I followed the instructions in the book to the letter but the server started complaining:

"POST /save/?ajax HTTP/1.1" 403 2332

Here is the code that might cause the trouble:

function bookmark_save() {
var item = $(this).parent();
var data = {
    url: item.find("#id_url").val(),
    title: item.find("#id_title").val(),
    tags: item.find("#id_tags").val()
};
$.post("/save/?ajax", data, function (result) {
    if (result != "failure") {
        item.before($("li", result).get(0));
        item.remove();
        $("ul.bookmarks .edit").click(bookmark_edit);
    }
    else {
        alert("Failed to validate bookmark before saving.");
    }
});
return false;

}

'/save/&ajax' is being handled by

if ajax:
    return render_to_response('bookmark_save_form.html', variables)

Here the bookmark_save_form.html:

<form id="save-form" method="post" action="/save/">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="save" />
</form>

As far as I understand things, I have to pass a csrf_token with the POST request. But I don't have a clue how.

Any advise on this would be great.

user852303
  • 43
  • 2
  • 4

5 Answers5

1

I am currently working through this book as well and ran into the exact same problem, BTW. Not for the first time either! Essentially what is happening is that the csrf token is not being passed via the Ajax request. So, the short and simple answer is that you need to include the csrf token is your ajax call. This is accomplished via this code block: https://docs.djangoproject.com/en/1.3/ref/contrib/csrf/#ajax

jQuery(document).ajaxSend(function(event, xhr, settings) {
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;
}
function sameOrigin(url) {
    // url could be relative or scheme relative or absolute
    var host = document.location.host; // host + port
    var protocol = document.location.protocol;
    var sr_origin = '//' + host;
    var origin = protocol + sr_origin;
    // Allow absolute or scheme relative URLs to same origin
    return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
        (url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
        // or any other URL that isn't scheme relative or absolute i.e relative.
        !(/^(\/\/|http:|https:).*/.test(url));
}
function safeMethod(method) {
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

if (!safeMethod(settings.type) && sameOrigin(settings.url)) {
    xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
});

I then included this as a .js file in my user_page.html. After that, I could make Ajax calls with impunity!

BigJim
  • 23
  • 6
  • @JIm, Many thanks for your answer. I am actually learning from the same book and came across the same problem. I tried your solution csrfmiddlewaretoken: '{{ csrf_token }}' but it still gives me the same error. Do I have to change it also in other places? Thanks – Houman May 26 '12 at 21:40
0

I am working through the book and just ran into the same problem. Here is the simplest solution, which has the benefit of not disabling Django's csrf protection or having to include decorators or fiddle with utilities like 'ensure_csrf_cookie'. It simply passes the token:

In the .js file you created to hold your custom jquery scripts, add the following pair to your 'data' var in in your bookmark_save() function:

csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].val()

So the resulting bookmark_save function looks like this:

function bookmark_save() {
    var item = $(this).parent();
    var data = {
        url: item.find("#id_url").val(),
        title: item.find("#id_title").val(),
        tags: item.find("#id_tags").val(),
        csrfmiddlewaretoken: document.getElementsByName('csrfmiddlewaretoken')[0].val()
    };
    $.post("/save/?ajax", data, function (result) {
        if (result != "failure") {
            item.before($("li", result).get(0));
            item.remove();
            $("ul.bookmarks .edit").click(bookmark_edit);
        }
        else {
            alert("Failed to validate bookmark before saving.");
        }
    });
    return false;
}
Jeff C.
  • 97
  • 1
  • 7
0

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def my_view(request):
...
Robert
  • 5,278
  • 43
  • 65
  • 115
Ashish Gupta
  • 1,153
  • 12
  • 14
0

I pulled this from a project already done. This is a contact form template. Mind you this is for django. Also please refer to the django book http://www.djangobook.com/en/2.0/ . All my questions have been answered by this book. It goes over everything. This shows exactly how to put in the csrf token (in a template):

<head> 
    <title>Contact Us</title> 
</head> 
<body> 
    <h1>Contact us</h1> 

{% if form.errors %}
    <p style="color: red;"> 
        Please correct the error{{ form.errors|pluralize }} below.
    </p> 
{% endif %}

<form action="" method="post"> 
    {% csrf_token %}
    <ul> 
        {{ form.as_ul }}
    </ul> 
    <input type="submit" value="Submit"> 
</form> 
</body> 

Also, change your value to submit instead of save, and instead of /save/ for action use post.....that might make it work.

TheChes44
  • 648
  • 1
  • 10
  • 21
  • Unfortunately this did'n solve my problem, but I found a way to turn off the csrf middleware. I know that protection against this kind of attack is probably a good thing but I can't deal with this kind of problem right now. When my understanding for django has advanced I will try this again... Thanks for the help! – user852303 Jul 21 '11 at 13:32
  • Actually it is a very very good thing. If you do not have csrf proctction, people can toy with the url and pretty much submit what they want, which could be faulty data, or even worse, code segments that could crash your server. Btw, try just render instead of render to response. READ THE DJANGO BOOK! Here is a link to exactly you need to read http://www.djangobook.com/en/2.0/chapter07/. – TheChes44 Jul 22 '11 at 02:27
-1

Create a Javascript file. I do not know how to format the code - sorry. Then load it after Jquery.

It is described here

Jagger
  • 10,350
  • 9
  • 51
  • 93
ekse
  • 1
  • 5