[Django] #29602: Django 2.0 breaks interop with Jinja2 forceescape filter

20 views
Skip to first unread message

Django

unread,
Jul 26, 2018, 7:17:37 PM7/26/18
to django-...@googlegroups.com
#29602: Django 2.0 breaks interop with Jinja2 forceescape filter
-------------------------------------------+------------------------
Reporter: Richard Eames | Owner: nobody
Type: Bug | Status: new
Component: Template system | Version: 2.0
Severity: Normal | Keywords:
Triage Stage: Unreviewed | Has patch: 0
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------------+------------------------
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 [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.

Django

unread,
Jul 27, 2018, 9:01:33 AM7/27/18
to django-...@googlegroups.com
#29602: Jinja2's forceescape filter doesn't work on Django's safe strings
---------------------------------+--------------------------------------

Reporter: Richard Eames | Owner: nobody
Type: Bug | Status: new
Component: Template system | Version: 2.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+--------------------------------------
Changes (by Tim Graham):

* 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>

Django

unread,
Jul 27, 2018, 10:33:40 AM7/27/18
to django-...@googlegroups.com
#29602: Jinja2's forceescape filter doesn't work on Django's safe strings
---------------------------------+--------------------------------------
Reporter: Richard Eames | Owner: nobody
Type: Bug | Status: new
Component: Template system | Version: 2.0
Severity: Normal | Resolution:

Keywords: | Triage Stage: Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------------+--------------------------------------

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>

Django

unread,
Jul 28, 2018, 3:19:21 PM7/28/18
to django-...@googlegroups.com
#29602: Jinja2's forceescape filter doesn't work on Django's safe strings
-------------------------------+------------------------------------

Reporter: Richard Eames | Owner: nobody
Type: Bug | Status: new
Component: Utilities | Version: 2.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted

Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------+------------------------------------
Changes (by Tim Graham):

* 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>

Django

unread,
Aug 2, 2026, 1:54:16 AM (24 hours ago) Aug 2
to django-...@googlegroups.com
#29602: Jinja2's forceescape filter doesn't work on Django's safe strings
---------------------------+-----------------------------------------
Reporter: no | Owner: Malachi Moody
Type: Bug | Status: assigned
Component: Utilities | Version: 2.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------+-----------------------------------------
Changes (by Malachi Moody):

* has_patch: 0 => 1
* owner: nobody => Malachi Moody
* status: new => assigned

Comment:

[https://github.com/django/django/pull/21718 PR]
--
Ticket URL: <https://code.djangoproject.com/ticket/29602#comment:4>

Django

unread,
Aug 2, 2026, 4:01:32 PM (10 hours ago) Aug 2
to django-...@googlegroups.com
#29602: Jinja2's forceescape filter doesn't work on Django's safe strings
---------------------------+-----------------------------------------
Reporter: no | Owner: Malachi Moody
Type: Bug | Status: assigned
Component: Utilities | Version: 2.0
Severity: Normal | Resolution:
Keywords: | Triage Stage: Accepted
Has patch: 1 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
---------------------------+-----------------------------------------
Changes (by Adam Zapletal):

* cc: Adam Zapletal (added)

--
Ticket URL: <https://code.djangoproject.com/ticket/29602#comment:5>
Reply all
Reply to author
Forward
0 new messages