I recently upgraded to Django 2.0, and shortly after had a complaint from
one of our users about a page not displaying correctly. I tracked down the
issue to a usage of Jinja's `forceescape` filter.
My usage is that we're displaying a preview of an email that will be sent
out, and we do this by using the `srcdoc` attribute of iframe, so our code
looks like:
{{{
<iframe srcdoc="{{ rendered_email | forceescape }}"></iframe>
}}}
The `rendered_email` variable is from a call to
`get_template(template_name).render(ctx)`, which returns a `SafeString`
object. Which makes sense since a rendered template should be html. And
since I want to display the email inside of html again, it needs to be
re-escape, logically with the `forceescape` filter.
However, a change from [https://code.djangoproject.com/ticket/27795 this
ticket]/[https://github.com/django/django/commit/ccfd1295f986cdf628d774937d0b38a14584721f
#diff-58d9f7a5099962dc591a93a47a671b72 this commit] causes the
`forceescape` filter to fail on the jinja side. `forcescape` calls `str()`
on it's argument to remove the "safety", then re-escapes it, however, the
aforementioned commit allow `SafeString` to bypass the assumption that
jinja makes when calling `str()`.
--
Ticket URL: <https://code.djangoproject.com/ticket/29602>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.
* cc: Claude Paroz (added)
Comment:
[https://github.com/pallets/jinja/blob/3bb2ef8b83cd04bcd77361a4d6a86b3bf4f89529/jinja2/filters.py#L87-L91
jinja.filters.do_forceescape()] uses
[https://github.com/pallets/markupsafe/blob/master/markupsafe/_native.py#L15-L34
markupsafe.escape()]. Since `str(SafeText)` now returns the `SafeText`,
the `hasattr(s, '__html__')` check in `escape()` returns True and no
escaping happens.
I think it's a legitimate issue as the behavior is certainly unexpected
(`SafeText` with the Django template language's `force_escape` filter
works as you would expect), however, I'm not sure what the best way
forward is as it's a bit late in the Django 2.0 lifecycle to revert the
original change.
--
Ticket URL: <https://code.djangoproject.com/ticket/29602#comment:1>
Comment (by Richard Eames):
I agree, it is a bit late in the 2.0 life cycle to revert it; a note in
the 2.0 change log would be very helpful for anyone else that's doing a
late upgrade like I was (while upgrading I was checking everything in the
release notes against our code base). I also assume it's too late in the
2.1 release cycle to fix in some way?
As a work around, I should either be able to use django's `force_escape`,
or manually wrap the variable in Jinja's `MarkUp()` function so that it
works with Jinja's `forceescape`.
--
Ticket URL: <https://code.djangoproject.com/ticket/29602#comment:2>
* component: Template system => Utilities
* stage: Unreviewed => Accepted
Comment:
Generally we don't document bugs in the release notes. :-)
It will be interesting to hear Claude's opinion on this issue.
--
Ticket URL: <https://code.djangoproject.com/ticket/29602#comment:3>