Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django render_to_string() ignores {% csrf_token %}

Tags:

django

I am trying to perform unit tests in Django. I have the following form in index.html:

<form method=POST>
  {% csrf_token %}
  <input name=itemT>
</form>

And I am testing if the view render the template correctly:

views.py

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

tests.py:

request = HttpRequest()

response = homePage(request)
if response:
    response = response.content.decode('UTF-8')

expectedHTML = render_to_string('index.html')
self.assertEqual(response, expectedHTML)

The response has a hidden input field with a csrf token; however, the expectedHTML does not (there is just a blank line at the place of {% csrf_token %}). So the assertion always fails.

Is it possible to have render_to_string() generate a csrf input field? If so, would the token of response the same as that of expectedHTML?

Or, is there any way to ignore the input field such that the test can be successful?

like image 943
Randy Tang Avatar asked Jan 06 '16 09:01

Randy Tang


People also ask

How to use CSRF token with render_to_string in Django?

To get the csrf token to work when using render_to_string, you need to supply the request object so that the context processors run. In Django 1.8+, you can simply pass the request as an argument return render_to_string ('index.html', request=request) On earlier versions, you can use a RequestContext.

How to prevent CSRF attacks in Django?

CSRF is a common attack, so Django has a very simple implementation to negate this attack. Django has a {% csrf_token %} tag that is implemented to avoid malicious attacks. It generates a token on the server-side when rendering the page and makes sure to cross-check this token for any requests coming back in.

Where is the CSRF middleware in Django?

The CSRF middleware is activated by default in the MIDDLEWARE setting. If you override that setting, remember that 'django.middleware.csrf.CsrfViewMiddleware' should come before any view middleware that assume that CSRF attacks have been dealt with.

Is it possible to show activity on a request in Django?

On earlier versions, you can use a RequestContext. Show activity on this post. Unfortunately Alasdair’s answer won't work with Django 1.10 as the csrf_token changes on each request.


2 Answers

To get the csrf token to work when using render_to_string, you need to supply the request object so that the context processors run.

In Django 1.8+, you can simply pass the request as an argument

return render_to_string('index.html', request=request)

On earlier versions, you can use a RequestContext.

from django.template import RequestContext
render_to_string('index.html', context_instance=RequestContext(request))
like image 130
Alasdair Avatar answered Oct 14 '22 02:10

Alasdair


Unfortunately Alasdair’s answer won't work with Django 1.10 as the csrf_token changes on each request. Please see this gist that works on 1.10. (Altered the code a bit to fix the typo from the original gist)

class HomePageTest(TestCase):

    @staticmethod
    def remove_csrf(html_code):
        csrf_regex = r'<input[^>]+csrfmiddlewaretoken[^>]+>'
        return re.sub(csrf_regex, '', html_code)

    def assertEqualExceptCSRF(self, html_code1, html_code2):
        return self.assertEqual(
            self.remove_csrf(html_code1),
            self.remove_csrf(html_code2)
        )
like image 34
Da CodeKid Avatar answered Oct 14 '22 02:10

Da CodeKid