Opened 7 years ago

Closed 6 years ago

Last modified 4 years ago

#8566 closed (fixed)

mark_safe not propagating from widgets to templates

Reported by: agirman Owned by: nobody
Component: Core (Other) Version: master
Severity: Keywords: mark_safe, safe string, escape, escaping, widgets
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: UI/UX:

Description (last modified by jacob)

I submitted the below to Django Users and Malcolm Tredinnick suggested I open a ticket. Essentially, when making custom widgets, I encountered a problem wherein despite marking things as safe strings, when I tried to render my forms in a template, they were beings escaped. Turning off auto escaping and piping to the safe filter weren't working, and I found that they were being escaped at a very low level. Namely, there is a call in the Widget.render function to django.forms.util.flatatt that is escaping everything. I don't know if this by design or not, but given the number of calls to mark_safe in the Widget module, I suspect not. It is preventing me from, for example, making JS function calls in widgets that require string arguments. I hope this helps.

Regards,

Alex.

====

Hi there,

I have been trying to get a function call into a widget argument, but
have not been able to at the template level, because it would appear
that my safe_strings are being escaped somewhere down in the
framework. I have created a widget and mark_safe'd an attribute
value, but no matter what, since it's pre-escaped by the time it
bubbles up to the template level, I can't not escape it (well... I
could use an html library to de-escape it, but that seems kludgy).

I've traced the execution and found the culprit to be the
django.forms.util.flatatt function. That is:

from django import forms
from django.utils.safestring import mark_safe

class MyWidget(forms.TextInput):
    def __init__(self, *args, **kwargs):
        attrs = kwargs.setdefault('attrs', {})
        attrs['safe_string'] = mark_safe("will o' the wisp")
        attrs['normal_string'] = "cat o' nine tails"
        super(MyWidget, self).__init__(*args, **kwargs)

w = MyWidget()
w.render("field_name", "")

#=> u'<input normal_string="cat o&#39; nine tails" type="text"
name="field_name" safe_string="will o&#39; the wisp" />'

You can see that both the unsafe and safe strings were escaped. I
don't know if this is intentional or not, but it prevents me from
making something like:

<input type="text" onBlur="myFunction('string_arg')">

because it is always escaping my single-quotes. Is this the desired
behavior? Anyway, like I said, the culprit is:

# django.forms.util

def flatatt(attrs):

"""
    Convert a dictionary of attributes to a single
string.
    The returned string will contain a leading space followed by
key="value",
    XML-style pairs.  It is assumed that the keys do not need to be
XML-
escaped.
    If the passed dictionary is empty, then return an empty
string.
    """
    return u''.join([u' %s="%s"' % (k, escape(v)) for k, v in
attrs.items()])  # <-- right there, the escape(v) call... should this
be conditional_escape?

Since there are a lot of calls to mark_safe scattered through the
widget and form-level calls used in rendering, I assume you're meant
to be able to mark something as safe down here and have it get to the
top level unaltered... no?

Change History (6)

comment:1 Changed 7 years ago by agirman

  • Needs documentation unset
  • Needs tests unset
  • Patch needs improvement unset

Alright, I should have previewed. Here is the code in a code block:

class MyWidget(forms.TextInput):
    def __init__(self, *args, **kwargs):
        attrs = kwargs.setdefault('attrs', {})
        attrs['safe_string'] = mark_safe("will o' the wisp")
        attrs['normal_string'] = "cat o' nine tails"
        super(MyWidget, self).__init__(*args, **kwargs)

w = MyWidget()
w.render("field_name", "")
#=> u'<input normal_string="cat o&#39; nine tails" type="text"
name="field_name" safe_string="will o&#39; the wisp" />'


comment:2 Changed 7 years ago by jacob

  • Description modified (diff)

(fixed formatting)

comment:3 Changed 7 years ago by mtredinnick

  • Resolution set to fixed
  • Status changed from new to closed

(In [8601]) Fixed #8566 -- Allow safe-strings in the "attrs" parameter to form widgets.

comment:4 follow-up: Changed 6 years ago by Denis_Cheremisov

  • milestone changed from 1.0 to 1.2
  • Resolution fixed deleted
  • Status changed from closed to reopened

It only propagates unicode safe strings (SafeUnicode), not simple strings (SafeString)

comment:5 in reply to: ↑ 4 Changed 6 years ago by kmtracey

  • milestone changed from 1.2 to 1.0
  • Resolution set to fixed
  • Status changed from reopened to closed

Replying to Denis_Cheremisov:

It only propagates unicode safe strings (SafeUnicode), not simple strings (SafeString)

What is "It"? The committed changeset for this ticket didn't do anything with Safe[Anything], it simply added a call to conditional_escape. conditional_escape, from a quick check, checks for SafeData, the base for both SafeUnicdoe and SafeString. So it isn't at all clear to me what you are trying to report. As the fix for this bug was checked in nearly a year ago, without any immediate reaction that it was broken, it would be best at this point to open a new ticket describing in detail whatever problem you are encountering.

comment:6 Changed 4 years ago by jacob

  • milestone 1.0 deleted

Milestone 1.0 deleted

Note: See TracTickets for help on using tickets.
Back to Top