django模板系统-源码分析-2

## django中的tag和filter ------------------- 《django模板系统-源码分析1》中提到每个BLOCK块对应的解析函数filter以及node交由用户定制,parser只负责调用。这就给了用户自定义tag的机会,用户可以像使用插件一样在模板中使用自定义的tag,甚至用户可以扩展模板语言成为一个较为完整的独立语言(需要完成函数的实现、变量值的再绑定等)。 ## django模板中的Library --------------------------- 首先看一下用户怎样实现自定义的tag和filter以及如何进行注册。这里注册的含义是指能够被Parser加载到局部变量`tags`和`filter`中。Parser在初始化方法中会将全局变量builtins中的Library实例中保存的tags和filter更新到局部变量中,而全局变量builtins在模块被加载的时候将默认的filters和tags加载进来。 undefined ## Library --------------- 为了方便自定义filter和tag,django定义了一些辅助函数和库类Library,用户按照一定的规则进行tag和filter的注册。 ### 注册filter Library类的filter方法可以作为装饰器以多种形式对自定义的filter函数进行注册。Library类的filter方法和filter\_function方法会互相调用,注意分场景分析。 自定义的filter函数分为两种,一种是简单的函数;另一种本身是装饰器。Library.filter\_function的作用就是获取自定义filter的名字,对于前一种直接获取函数的名字;对于后一种则尽量获取其内部被装饰函数\_decorated\_function的名字。如果用户自定义的filter本身是个装饰器,最好把装饰器的内部变量\_decorated\_function设置为被装饰的函数,例如。 undefined 调用Library.filter进行自定义filter函数的注册有多种形式。 1.第一种,直接调用形式。 undefined 2.第二种,不带参数的函数式调用形式 undefined 3.第三种,指定自定义filter的名字 undefined 4.第四种,指定其他参数 undefined 无论何种调用方式,都会进入Libaray.fiter的最后一个分支进行三部分的处理。第一部分注册filter函数`self.filters[name]=filter_func`;第二部分将传入的参数设置为filter\_func以及内部装饰函数的属性,这个filter\_func不一定是用户自定义的filter函数,在多数情况下是装饰了自定义filter的装饰器;第三部分设置名称`filter_func._filter_name=name`。 ### 注册tag 自定义tag时,用户需要实现两个部分。一个用户自定义的继承了Node的类实现此tag的语义;另一个用户定义的解析函数,将对应tag的BLOCK类型token解析为语法树并返回对应的Node,即实现此tag的语法解析。我们以{% firstof %}为例说明,firstof会返回给定参数中第一个为真的变量`{% firstof 0 1 2 3 %} => 1`。 undefined ## defaultfilters ------------------------ 选取几个比较常用的filter函数进行分析。 ### lower undefined lower函数将字符串转换为小写,stringfilter是装饰器以统一处理字符的安全问题。需要注意带双引号的变量代表字符,不然代表一个变量。`{{ "ABC"|lower }} => abc`;`{{ ABC|lower }} => ''`,后一个因为ABC代表变量且不存在而返回空字符串。 ### yesno undefined ## defaulttags ---------------------- defaultfilters的逻辑比较简单,可以通过源码获知。而defaulttags则比较复杂,不仅因为包含两部分(语义分析和语法分析),还因为tags的种类较多,所有的逻辑功能都通过tags提供,例如判断、with、循环等。下面简单分析几种tag的实现。 ### with with 可以在模板中自定义变量,或者是给变量取别名。 undefined 首先看with的语法部分,do_with函数(django.template.defaulttags.do_with)。 undefined 然后继续看with的语义部分WithNode。 undefined 可以看到,with的实现非常清楚。do_with实现语法解析,WithNode实现语义求值,Context实例保存上下文的环境变量。 ### for for 可以在模板中进行循环求值。通过with的分析,可以简单将for理解为,设置同一(几)个环境变量的值(Context)、对子作用域求值(nodelist)、直到耗尽所有的环境变量的值、最后对所有值拼接。 undefined do\_for将for分解为了4个部分,每个部分在实现语义的时候分别处理。 undefined ## 总结 ------------ 至此简单分析了django的template框架以及自定义filter和tag的实现。依托于django模板框架的良好架构,用户自定义的filter和tag十分方便简洁。