Opened 6 years ago
Last modified 6 years ago
#29602 new Bug
Jinja2's forceescape filter doesn't work on Django's safe strings
Reported by: | no | Owned by: | nobody |
---|---|---|---|
Component: | Utilities | Version: | 2.0 |
Severity: | Normal | Keywords: | |
Cc: | Claude Paroz | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Not sure if this is a Django bug, jinja bug, or something I need to change for upgrading to Django 2.0, but since it was a Django commit causes it, I'm reporting here first.
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 this ticket/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()
.
Change History (3)
comment:1 by , 6 years ago
Cc: | added |
---|---|
Summary: | Django 2.0 breaks interop with Jinja2 forceescape filter → Jinja2's forceescape filter doesn't work on Django's safe strings |
comment:2 by , 6 years ago
I agree, it is a bit late in the 2.0 life cycle to revert it; but 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
.
comment:3 by , 6 years ago
Component: | Template system → Utilities |
---|---|
Triage Stage: | Unreviewed → Accepted |
Generally we don't document bugs in the release notes. :-)
It will be interesting to hear Claude's opinion on this issue.
jinja.filters.do_forceescape() uses markupsafe.escape(). Since
str(SafeText)
now returns theSafeText
, thehasattr(s, '__html__')
check inescape()
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'sforce_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.