7

In my users page, i have in place editing with ajax. And when i click edit, it works fine. But when i submit the form, it don't do anything. When i checked, this is the error:

CSRF verification failed. Request aborted.

So, how do I place {% csrf_token %} in my javascript? Please advice. Thank you.

edit.js:

function bookmark_edit() {
    var item = $(this).parent();
    var url = item.find(".title").attr("href");
    item.load("/save/?ajax&url=" + escape(url), null, function () {
        $("#save-form").submit(bookmark_save);
        });
    return false;
    }

$(document).ready(function () {
    $("ul.bookmarks .edit").click(bookmark_edit);
    });

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_form.html:

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

user_page.html:

{% extends "base.html" %}
{% block external %}
    <script type = "text/javascript" src="{% static "assets/js/bookmark_edit.js" %}"></script>
{% endblock %}
{% block title %} {{username}} {% endblock %}
{% block head %} Bookmarks for {{username}} {% endblock %}
{% block content %}
    {% include "bookmark_list.html" %}
{% endblock %}

view.py:

@login_required(login_url='/login/')
def bookmark_save_page(request):
    ajax = request.GET.has_key('ajax')
    if request.method == 'POST':
        form = BookmarkSaveForm(request.POST)
        if form.is_valid():
            bookmark = _bookmark_save(request, form)
            if ajax:
                variables = RequestContext(request, {
                    'bookmarks':[bookmark],
                    'show_edit':True,
                    'show_tags':True
                    })
                return render_to_response('bookmark_list.html', variables)
            else:
                return HttpResponseRedirect('/user/%s/' % request.user.username
                    )
        else:
            if ajax:
                return HttpResponseRedirect('failure')
    elif request.GET.has_key('url'):
        url = request.GET['url']
        title = ''
        tags = ''

        try:
            link = Link.objects.get(url=url)
            bookmark = Bookmark.objects.get(
                link=link,
                user = request.user
                )
            title = bookmark.title
            tags = ' '.join(
                tag.name for tag in bookmark.tag_set.all()
                )
        except ObjectDoesNotExist:
            pass
        form = BookmarkSaveForm({
            'url':url,
            'title':title,
            'tags':tags
            })
    else:
        form = BookmarkSaveForm()

    variables = RequestContext(request, {
        'form': form
        })
    if ajax:
        return render_to_response(
            'bookmark_save_form.html',
            variables
            )
    else:
        return render_to_response('bookmark_save.html',variables)
Karl
  • 1,689
  • 3
  • 15
  • 23

4 Answers4

8

You are not sending the server generated csrf_token for the POST to verify the validity of the data. Hence the error.

As a part of the data part of the request, you need to send the token

csrfmiddlewaretoken: '{{ csrf_token }}' 

Something like this

var data = {
    url: item.find("#id_url").val(),
    title: item.find("#id_title").val(),
    tags: item.find("#id_tags").val(),
    csrfmiddlewaretoken: '{{ csrf_token }}' 
};

Or you could simply do:

var data = $('form').serialize()

if you want to send the whole form as a dictionary

karthikr
  • 97,368
  • 26
  • 197
  • 188
  • I tried `csrfmiddlewaretoken: '{{ csrf_token}}'` But it didn't quite helped. And could you plz explain how to send whole as a dictionary? – Karl Jul 20 '13 at 20:44
  • 1
    `var data = $('form').serialize()` would send the whole form as a dictionary. – karthikr Jul 20 '13 at 21:01
  • Thanks! This one worked! Bdw can you suggest me any good books to read for both up to date django version and javascript? – Karl Jul 20 '13 at 21:54
  • I learnt jQuery and Django in depth individually, which helped me tailor the two together to my needs. I would recommend you reading up lots of available blogs online that can help you put the pieces to gether. If you are stuck, StackOverflow is always there to help you. – karthikr Jul 20 '13 at 22:17
  • Does it have, csrf related problems in the book? – Karl Jul 20 '13 at 22:22
  • Yes. Djangoproject does cover it. – karthikr Jul 21 '13 at 00:17
3

var csrftoken = Cookies.get('csrftoken');

xhr.setRequestHeader("X-CSRFToken", csrftoken);

enter link description here

user5824405
  • 121
  • 6
1

This is what I use. Not sure if it's applicable in your situation though.

// sending a csrftoken with every ajax request
function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    crossDomain: false, // obviates need for sameOrigin test
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type)) {
            xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
        }
    }
});
dan-klasson
  • 13,734
  • 14
  • 63
  • 101
0
var CSRF_TOKEN = '{{ csrf_token }}';  

Past this is js file

Tyler2P
  • 2,324
  • 26
  • 22
  • 31