Django:奇怪的mark_safe行为?

时间:2010-04-08 02:24:10

标签: python django

我写了这个小函数来写出HTML标签:

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

哪个很好用,但后来我在efficient string concatenation上阅读了这篇文章(我知道这并不重要,但我想要一致性)并决定更新我的脚本:

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())

但是当我尝试从我的模板中渲染时,现在我的HTML得到转义。其他一切都完全一样。如果我用return mark_safe(unicode(s.getvalue()))替换最后一行,它可以正常工作。我检查了s.getvalue()的返回类型。它应该是str,就像第一个函数一样,为什么会失败?

SafeString(s.getvalue())也失败,但SafeUnicode(s.getvalue())成功。


我还想指出,我在{em> no 奇怪行为的不同函数中使用了return mark_safe(s.getvalue())


“调用堆栈”如下所示:

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'两次,我认为这可能是问题,但我也尝试删除它......我真的不知道是什么导致了这个问题,但是解决它并不困难,所以我想我不会担心它。

1 个答案:

答案 0 :(得分:7)

小部件的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'>