代码之家  ›  专栏  ›  技术社区  ›  mpen

Django:奇怪的Mark_安全行为?

  •  3
  • mpen  · 技术社区  · 15 年前

    我写了一个写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()) .


    我还想指出 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 “D两次,我想可能是问题所在,但我也试过把它去掉…..我真的不知道是什么原因造成的,但这不是太难工作,所以我想我不会担心。

    1 回复  |  直到 14 年前
        1
  •  7
  •   dready    14 年前

    这个 render 小部件的方法由 BoundField.__unicode__ 函数,它返回safestring而不是 unicode )

    Django的许多地方(例如 django.template.VariableNode.render )会打电话来的 force_unicode 在字段实例本身上。这样做的效果是 unicode(instance.__unicode__()) ,所以即使 instance.__unicode__() 返回A SafeString 对象,它将成为 统一码 对象。

    为了说明这一点,请看下面的代码片段:

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