2
votes

I have a form in my html:

<form id="form" action="" method="post"> {% csrf_token %}
   <div>{{form.input1}}</div>
   <div>{{form.input2}}</div>
   <div>{{form.input3}}</div>
   <input type="submit" class="btn" name="submit" value="submit">
</form>

and in my urls.py:

urlpatterns = [
    url(r'^$', views.MyView.as_view(success_url='/'), name='index'),
]

and sometimes when I hit submit, the csrf token gets triggered and says csrf token missing or incorrect.

First of all how is this possible? The doc says:

This should usually only be seen when there is a genuine Cross Site Request Forgery, or when, due to a programming error, the CSRF token has not been included with a POST form.

From what I see it's implemented correctly.

The error message further says

  • Your browser is accepting cookies

it does

  • The view function passes a request to the template's render method

According to the doc I have that.

  • In the template there is a {%csrf_token%} template tag inside each POST form that targets an internal URL

it is indeed, but that's the whole point of having a csrf token right?

  • 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.

According to the doc this is activated by default.

So why does it trigger sometimes (very rarely)?

2
Maybe something is happening to the form elements (inputs being wiped?)bozdoz
You'll need to at least show an example of your view function passing the request.Daniel Roseman

2 Answers

3
votes

Since you say that the error only occurs sometimes, I think the problem might be that you opened the page with the form, logged in on another tab, then submitted the form.

This causes an error because the csrf token is updated when you log in. Unfortunately, you can't really do anything about this.

2
votes

Are you rendering your form dynamically or something like that? Django only replaces {% csrf_token %} with the hidden input field and injects csrftoken cookie when that tag is present in the template from the beginning.

First try decorating your views with:

from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def index(request):
    return render(request, 'index.html')

This will always inject the cookie.

If you really are manipulating the form dynamically you need to use csrftoken cookie to retrieve the csrf token manually and then submit it along the form either using hidden field (extra request param) or a header, as stated in the docs.