SpoonMeiser
SpoonMeiser

Reputation: 20457

How to use csrf_token in django template included with limited context

Django templates allow you to include other templates to compose your page. This is particularly useful when you want to render the entire page, but might want to re-load part of it using AJAX, and don't want to move all render logic into javascript (or worse: duplicate it in javascript).

Including a template can look like this:

{% include "template.html" %}

However, if that template might be used by different views, it's likely that your context isn't just a superset of the context for that template. So Django lets you specify the context for the template too.

Because I want to avoid accidentally introducing different behaviour when the template is rendered by being included in another template, and when the template is rendered as the primary template for a view, it also makes sense to me to use the only option to avoid it accessing the parent template's context.

So my include looks like this:

{% include "sub_template.html" foo=sub_context.foo bar=sub_context.bar only %}

However, adding that only causes a problem: {% csrf_token %} no longer works in that template because I guess some of the hidden magic that Django does has been excluded.

The error that Django logs is

UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext.

The parent template is rendered with a RequestContext, and when the sub template is rendered as the primary template, and not included, the error doesn't occur.

The most obvious work-around to this problem is to not using the only option to include, which seems a shame. Is there a better way of working around this problem?

Upvotes: 4

Views: 1747

Answers (1)

Alex Williams
Alex Williams

Reputation: 116

I had the same issue, and agree that not using only is not an ideal solution.

Turns out {{csrf_token}} works just fine in the parent template so you can use this to send the naked csrf_token across to the included template:

{% include "sub_template.html" foo=sub_context.foo csrf_token=csrf_token only %}

Then the {% csrf_token %} tag works fine on the other side and uses that value to output the full hidden input element. And you still get the advantages of using only in the include.

My answer was found from experimenting with the answers to this question: Django's {{ csrf_token }} is outputting the token value only, without the hidden input markup

Upvotes: 10

Related Questions