8
$.ajax({
    url:'/',
    type: "POST",
    data: {name: 'name', age: 'age'},
    success:function(response){},
    complete:function(){},
    error:function (xhr, textStatus, thrownError){}
});

And in views.py:

class SomeView(generic_views.TemplateView):
    template_name = 'something.html'

    def get(self, request, *args, **kwargs):
        ...something...
        return self.render_to_response(context)

    def post(self, request, *args, **kwargs):
        name = request.POST['name']
        age = request.POST['age']
        ...something...

And I get: [05/Oct/2012 12:03:58] "POST /something/ HTTP/1.1" 403 2294

I'd like to send this data(name and age) via jQuery to this post function in "SomeView". This is the same view as the loaded template, just the request type is different. On get() the template loads and on post, the post() function should be called. Is it possible? I've checked other questions and got this solution. It was supposed to be working. What am I doing wrong?

premik91
  • 89
  • 1
  • 1
  • 7

4 Answers4

12

The answer to your question what you are doing wrong, is: not much!

Django returns a 403 response (Forbidden) if an incoming POST request fails Csrf checks. You can do this through jQuery's ajaxSetup, code snippets are found here

The reason that this DOES work on a GET request, is simply that GET requests are not checked by the csrf middleware.

As it seems you are building a form here, another thing to consider is using class based forms. They handle get/post and also parameter validation for you. Very neat. Especially when you are making forms to edit/create/delete model instances, in which case you can embrace the power of ModelForms and CreateViews. Very neat.

It might take some time to get the hang of those generic class based views. But it's very well worth it.

A.J.Rouvoet
  • 1,203
  • 1
  • 14
  • 29
  • Yeah on other sites I am using FormView. But in this case I can't(long story). :) Now the thing works, but in terminal I see [05/Oct/2012 15:08:11] "POST /something/ HTTP/1.1" 500 9499 – premik91 Oct 05 '12 at 13:08
  • 500 is simply a server error. This can be due to any python error in your post method. – A.J.Rouvoet Oct 05 '12 at 13:42
  • It does. But not in a way that you can see. The stacktrace and other django debugging info is returned as a HttpResponse on your ajax request. You can log it by logging the response to it in the jquery.ajax error callback. It might be easier to use firebug/chrome developers tool to view what exactly happened. Those tools will give you the exact parameters passed to the service and the response of the server, which will be the Django debugging info. – A.J.Rouvoet Oct 05 '12 at 20:42
  • I've managed to solve that error too. I just had to add "return self.render_to_response({})" to the end of post() function. – premik91 Oct 06 '12 at 17:47
10

You need to include a CSRF (cross-site request forgery) token in your ajax call. This is well documented here: https://docs.djangoproject.com/en/dev/ref/contrib/csrf/

or, if you want to use a quick fix, use the @csrf_exempt decorator for your view:

from django.views.decorators.csrf import csrf_exempt

@csrf_exempt
def my_view(request):
   ...
Tharusha
  • 635
  • 8
  • 25
Hoff
  • 38,776
  • 17
  • 74
  • 99
  • Adding `@csrf_exempt` decorator for the view to quick fix is working well and fascinating fact. – Tharusha May 09 '18 at 16:51
  • Thanks for the exempt. Obv don't want that in prod 99% of the time, but in dev I don't want to spend time setting that up and want to get to actually prototyping. – logicOnAbstractions Aug 27 '21 at 13:15
4

Within a Django template you can add this...

{% csrf_token %}

Which will output something like this to your page html...

<input type="hidden" name="csrfmiddlewaretoken" value="ckhUdNOTj88A...hfTnREALlks2kz">

Then using Javascript you can simply find this input and get its value - something like this non jQuery example...

var el = document.getElementsByName("csrfmiddlewaretoken");
csrf_value = el[0].getAttribute("value");

Lastly add the csrf_value to your jQuery AJAX post form data line like so...

data: {name: 'name', age: 'age', csrfmiddlewaretoken: csrf_value},

Here's a working jsFiddle concept: https://jsfiddle.net/vdx1Lfpc/18/

JxAxMxIxN
  • 1,711
  • 1
  • 17
  • 20
1

I read on another post that you can do something like this:

$.ajax({
    method: "POST",
    url: "{% url 'some_route' %}",
    headers: {'X-CSRFToken': '{{ csrf_token }}'},
    contentType: "application/json",
    dataType: 'json',
    data: {name:$('#id_name').val()}
})
.fail(function(message) {
    alert('error');
})
.done(function(data) {
    alert(data);
});
Robert Johnstone
  • 5,431
  • 12
  • 58
  • 88