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?
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.
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.
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.
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.
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))
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)
)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With