django模板自动转义(autoescape)机制
2011 3 14 11:57 PM 0条评论 297次查看 0顶 0踩
分类:笔记 标签:django, python
一、状态机制
django把通过模板过滤器(filter)的数据分为3种状态:
1、原始态(Raw string)
即普通的str或unicode类型。如果开启了自动转义,这种数据会被自动转义;如果关闭了自动转义,那么这种数据则原样输出,不做任何改变。
2、安全态(Safe string)
这是已经做过了所有必要的转义。在它再次被修改前,是安全的,输出时不会再被转义。如果处于这个状态的数据经又过了某个过滤器,状态可能会发生改变。主要是SafeString和SafeUnicode,它们是SafeData的子类型。
3、需转义态(Strings marked as "needing escaping")
被标记为“需转义态”的数据,在输出时都会被转义。主要是EscapeString和EscapeUnicode,它们是EscapeData的子类型。
在开启自动转义的情况下,django模板数据过滤器链的尾端,都会根据数据状态进行转义,凡是处于“安全态”的数据都原样输出,凡是处于“原始态”或“需转义态”的数据都会被转义,并使之转换为“安全态”。最后只有处于“安全态”的数据才会最终将其内容输出至html文档中。在数据通过过滤器时,过滤器根据所提供的数据状态判断是否进行转义或其他操作,并根据转义或操作的结果决定是否改变数据状态。
二、内部处理流程
假设有源数据(data),要通过过滤器。
- 如果过滤器的 needs_autoescape 属性为True,则给该过滤器准备一个 autoescape 参数。
- 运行过滤器,得到一个新数据(new_data)。如果提供了autoescape参数,过滤器就可以根据autoescape的值(True/False)做必要的处理。
- 如果过滤器的is_safe属性为True,并且源数据(data)是SafeData实例,则将新数据(new_data)转换成“安全态”。否则,如果源数据(data)是EscapeData,则将新数据转换为“需转义态”。
- 返回处理好的新数据(new_data),即下一个过滤器的源数据。
- 进入下一个过滤器,重复步骤1-4 直至过滤器链中最后一个过滤器。
- 判断过滤器链条最终输出数据(final_data)的状态,如果final_data为“安全态”,则原样渲染到网页,如果final_data为其他状态,则会对final_data进行转义,并渲染到网页。
三、过滤属性的作用及用法
1、is_safe
仅当过滤器中未引入任何不安全数据时使用。但要注意如果替换或删除某些字符也会导致不安全,例如,将已经处于安全状态的数据中的链接<a>去掉了一个大于号变成<a。因此使用这个属性必须要保证真的不会对已经处于安全态的数据造成破坏。
过滤器定义:
@register.filter
def safe_filter(value):
'%s <a href="#">x</a>' % value
return nv
safe_filter.is_safe=True模板:
<!--
python code:
data='<a href="http://www.google.com">Google</a>'
-->
{% autoescape on %}
<ul>
<li>{{ data }}</li>
<li>{{ data|safe_filter}}</li>
<li>{{ data|safe}}</li>
<li>{{ data|safe|safe_filter }}</li>
</ul>
{% endautoescape %}显示为:2、needs_autoescape
凡是带有这个属性的过滤器,必须提供一个名为autoescape的参数。值为True代表开启了自动转义,False代表关闭了自动转义。过滤器中一般会用conditional_escape与mark_safe等方法来辅助处理各类状况。
conditional_escape(html),根据状态转义,如果html状态为“安全态”,就直接返回html,否则就对html进行转义。
mark_safe(s),将s转换成“安全态”。
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
def initial_letter_filter(text, autoescape=None):
first, other = text[0], text[1:]
#如果开启了自动转义,就根据text的状态进行转义
if autoescape:
esc = conditional_escape
else:
esc = lambda x: x
result = '<strong>%s</strong>%s' % (esc(first), esc(other))
return mark_safe(result)
initial_letter_filter.needs_autoescape = True参考:
More

