Django: Odd mark_safe behavior?

I wrote this little function for writing HTML tags:

def html_tag(tag, content=None, close=True, attrs={}):
    lst = ['<',tag]
    for key, val in attrs.iteritems():
        lst.append(' %s="%s"' % (key, escape_html(val)))
    if close:
        if content is None: lst.append(' />')
        else: lst.extend(['>', content, '</', tag, '>'])
    else:
        lst.append('>')
    return mark_safe(''.join(lst))

This worked fine, but then I read this article on efficient string concatenation (I know it doesn't really matter for this, but I wanted consistency) and decided to update my script:

def html_tag(tag, body=None, close=True, attrs={}):
    s = StringIO()
    s.write('<%s'%tag)
    for key, val in attrs.iteritems():
        s.write(' %s="%s"' % (key, escape_html(val)))
    if close:
        if body is None: s.write(' />')
        else: s.write('>%s</%s>' % (body, tag))
    else:
        s.write('>')
    return mark_safe(s.getvalue())

But now my HTML has escaped when I try to display it from my template. Everything else is exactly the same. It works correctly if you replace the last line with return mark_safe(unicode(s.getvalue())). I checked the return type s.getvalue(). It should be strlike the first function, so why doesn't it succeed?

Also, the failure SafeString(s.getvalue())fails SafeUnicode(s.getvalue()).


I would also like to point out that I used return mark_safe(s.getvalue())in another function without any odd behavior.


" " :

class Input(Widget):
    def render(self):
        return html_tag('input', attrs={'type':self.itype, 'id':self.id,
            'name':self.name, 'value':self.value, 'class':self.itype})
class Field:
    def __unicode__(self):
        return mark_safe(self.widget.render())

{{myfield}} . , mark_safed 'd, , , , ... , , , , .

+3
1

render BoundField.__unicode__, SafeString ( unicode.)

Django (, django.template.VariableNode.render) force_unicode . unicode(instance.__unicode__()), instance.__unicode__() SafeString, unicode .

, :

from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe

class Foo(object):
    def __unicode__(self):
        return mark_safe("foo")

foo = Foo()
print "foo =", type(foo)

ufoo = unicode(foo)
print "ufoo =", type(ufoo)

forced_foo = force_unicode(foo)
print "forced_foo =", type(forced_foo)


bar = mark_safe("bar")
print "bar =", type(bar)

forced_bar = force_unicode(bar)
print "forced_bar =", type(forced_bar)

:

foo = <class 'testt.Foo'>
ufoo = <type 'unicode'>
forced_foo = <type 'unicode'>
bar = <class 'django.utils.safestring.SafeString'>
forced_bar = <class 'django.utils.safestring.SafeUnicode'>
+7

Source: https://habr.com/ru/post/1740250/


All Articles