问题
I have read Django - CSRF verification failed and several questions (and answers) related to django and POST method. One of the best-but-not-working-for-me answer is https://stackoverflow.com/a/4707639/755319
All of the approved answers suggest at least 3 things:
- Use RequestContext as the third parameter of render_to_response_call
- Add {% csrf_token %} in every form with POST method
- Check the MIDDLEWARE_CLASSES in settings.py
I've done exactly as suggested, but the error still appeared. I use django 1.3.1 (from ubuntu 12.04 repository) and python 2.7 (default from ubuntu)
This is my View:
# Create your views here.
from django.template import RequestContext
from django.http import HttpResponse
from django.shortcuts import render_to_response
from models import BookModel
def index(request):
return HttpResponse('Welcome to the library')
def search_form(request):
return render_to_response('library/search_form.html')
def search(request):
if request.method=='POST':
if 'q' in request.POST:
q=request.POST['q']
bookModel = BookModel.objects.filter(title__icontains=q)
result = {'books' : bookModel,}
return render_to_response('library/search.html', result, context_instance=RequestContext(request))
else:
return search_form(request)
else:
return search_form(request)
and this is my template (search_form.html):
{% extends "base.html" %}
{% block content %}
<form action="/library/search/" method="post">
{% csrf_token %}
<input type="text" name="q">
<input type="submit" value="Search">
</form>
{% endblock %}
I've restarted the server, but the 403 forbidden error is still there, telling that CSRF verification failed.
I've 2 questions:
- How to fix this error?
- Why is it so hard to make a "POST" in django, I mean is there any specific reason to make it so verbose (I come from PHP, and never found such a problem before)?
回答1:
Try putting RequestContext in the search_form view's render_to_response:
context_instance=RequestContext(request)
回答2:
I maybe wrong however I found the above solutions rather complex.
what worked for me was simply including my csrf token into my post request.
$.ajax({
type: "POST",
url: "/reports/",
data: { csrfmiddlewaretoken: "{{ csrf_token }}", // < here
state:"inactive"
},
success: function() {
alert("pocohuntus")
console.log("prototype")
}
})
回答3:
The easiest way to avoid such problems is to use the render shortcut.
from django.shortcuts import render
# .. your other imports
def search_form(request):
return render(request, 'library/search_form.html')
def search(request):
q = request.GET.get('q')
results = BookModel.objects.all()
if q:
results = results.filter(title__icontains=q)
return render(request, 'library/search.html', {'result': results})
回答4:
This answer is for people that may encounter this same problem in the future.
The CSRF {{csrf_token}}
template tag that is required for forms in Django prevent against Cross Site Request Forgeries. CSRF makes it possible for a malicious site that has been visited by a client's browser to make requests to your own server. Hence the csrf_token provided by django makes it simple for your django server and site to be protected against this type of malicious attack. If your form is not protected by csrf_token, django returns a 403 forbidden page. This is a form of protection for your website especially when the token wasn't left out intentionally.
But there are scenarios where a django site would not want to protect its forms using the csrf_token. For instance, I developed a USSD application and a view function is required to receive a POST request from the USSD API. We should note that the POST request was not from a form on the client hence the risk of CSRF impossible, since a malicious site cannot submit requests. The POST request is received when a user dials a USSD code and not when a form is submitted.
In other words, there are situations where a function will need to get a POST request and there would not be the need of {{csrf_token}}.
Django provides us with a decorator @csrf_exempt
. This decorator marks a view as being exempt from the protection ensured by the middleware.
from django.views.decorators.csrf import csrf_exempt
from django.http import HttpResponse
@csrf_exempt
def my_view(request):
return HttpResponse('Hello world')
Django also provides another decorator that performs the same function with {{csrf_token}}
, but it doesn't reject incoming request. This decorator is @requires_csrf_token
. For instance:
@requires_csrf_token
def my_view(request):
c = {}
# ...
return render(request, "a_template.html", c)
The last decorator that will be mentioned in this post does exactly the same thing as {{csrf_token}} and it is called @csrf_protect
. However, the use of this decorator by itself is not best practice because you might forget to add it to your views. For instance:
@csrf_protect
def my_view(request):
c = {}
# ...
return render(request, "a_template.html", c)
Below are some links that will guide and explain better.
https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/#module-django.views.decorators.csrf
https://docs.djangoproject.com/en/1.7/ref/contrib/csrf/
http://www.squarefree.com/securitytips/web-developers.html#CSRF
回答5:
The response is 403 bcoz, django requires a csrf token (included in the post data) in every POST request you make.
There are various ways to do this such as:
Acquiring the token from cookie and the method has been explained in article enter link description here
or
You can access it from DOM using {{ csrf_token }}, available in the template
So now using the second method:
var post_data = {
...
'csrfmiddlewaretoken':"{{ csrf_token }}"
...
}
$.ajax({
url:'url',
type:'POST'
data:post_data,
success:function(data){
console.log(data);
},
error:function(error){
console.log(error);
}
});
回答6:
You also can use
direct_to_template(request, 'library/search.html', result)
instead of
render_to_response('library/search.html', result, context_instance=RequestContext(request))
because direct_to_template
adds RequestContext
automatically. But note that direct_to_template
is going to be deprecated and django offers to use CBV TemplateView
instead.
RequestContext allows you to use context processors. And this is your mistake: {% csrf_token %}
outputed empty string and you got 403.
回答7:
You need to use RequestContext
with your response
for example
in view.py
file
from django.template import RequestContext
def home(request):
return render_to_response('home.html',RequestContext(request, {}))
来源:https://stackoverflow.com/questions/10663446/post-method-always-return-403-forbidden