user1050619
user1050619

Reputation: 20906

Django POST request failing

I get an error while using a POST in my form even though I have added a csrf_token to my form....

Error

Forbidden (403)

CSRF verification failed. Request aborted.

Help

Reason given for failure: CSRF cookie not set.

In general, this can occur when there is a genuine Cross Site Request Forgery, or when Django's CSRF mechanism has not been used correctly. For POST forms, you need to ensure: •Your browser is accepting cookies. •The view function uses RequestContext for the template, instead of Context. •In the template, there is a {% csrf_token %} template tag inside each POST form that targets an internal URL. •If you are not using CsrfViewMiddleware, then you must use csrf_protect on any views that use the csrf_token template tag, as well as those that accept the POST data.

You're seeing the help section of this page because you have DEBUG = True in your Django settings file. Change that to False, and only the initial error message will be displayed.

You can customize this page using the CSRF_FAILURE_VIEW setting.

views.py

def search_form(request):
    return render_to_response('search_form.html')
def search(request):
    print 'request.post=', request.POST
    print 'request.get=', request.GET
    print 'request.method=', request.META.get('REQUEST_METHOD')
    if 'q' in request.GET:
        message = 'You searched for :%r' % request.GET['q']
    else:
        message = 'You submitted an empty form'

    return HttpResponse(message)



search-form.html

<html>
<head>
    <title>Search</title>
</head>
<body>
    <form action="/polls/search/" method="post">{% csrf_token %}
        <input type="text" name="q">
        <input type="submit" value="Search">
    </form>
</body>
</html>

urls.py
urlpatterns = patterns('',url(r'^$',views.index,name='index'),
        url(r'^meta/',views.display_meta,name='meta'),
        url(r'^search-form/$',views.search_form),
        url(r'^search/',views.search),

Upvotes: 0

Views: 2999

Answers (2)

Aidan Ewen
Aidan Ewen

Reputation: 13328

You haven't added the token to your form.

You've added the code {% csrf_token %}, but django.core.context_processors.csrf aren't being used so the template tag isn't actually outputting anything (template tags fail silently).

Instead of using HttpResponse, you need render_to_response() (with a RequestContext) or just render() (which handles the RequestContext for you).

On a different note, you don't need two views for this. search should handle both rendering the form and processing the form -

from django.shortcuts import render

def search(request):
    if request.method == POST:
        print 'request.post=', request.POST
        print 'request.get=', request.GET
        print 'request.method=', request.META.get('REQUEST_METHOD')
        if 'q' in request.GET:
            message = 'You searched for :%r' % request.POST['q']
        else:
            message = 'You submitted an empty form'
        return render(request, 'search_form.html', {'message': message})
    return render(request, 'search_form.html')

Then add the {{ message }} variable to your search_form.html template - probably in some sort of if statement to achieve the same thing you're doing now -

<body>
    {% if message %}
        <div> {{ message }} </div>
    {% else %}
        <form action="/polls/search/" method="post">{% csrf_token %}
            <input type="text" name="q">
            <input type="submit" value="Search">
        </form>
    {% endif %}
</body>

Upvotes: 0

f4nt
f4nt

Reputation: 2671

You want to see point #3 here. You're returning a plain HttpResponse, so I think the csrf context processor is being skipped. You might want to consider using django.shortcuts.render instead. Also, in your template your form method is "post", but in your view you're checking request.GET. That's not related to the CSRF issue you're having, but is something you want to fix probably.

Upvotes: 2

Related Questions