django探秘 (2)个性化模板tag

本文深入探讨了模板系统的编译与渲染过程,包括如何实现个性化tag,并详细解释了语法解析和自动转义机制。通过实例展示了如何注册自定义tag及传递模板变量到tag,旨在帮助开发者理解并应用模板系统。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  1.  
    1. 概念:模板系统两步工作:编译和渲染,因此个性化tag必须指定编译和渲染的具体工作

      1. 编译:将raw文本流分割成node,每个node都是django.template.Node类的一个实例,都有一个render()方法,最终生成一个编译好的template对象,其实一个编译好的template对象就是一个node的列表

      2. 渲 染:当调用一个编译好的template对象后,如果用context对象(这是一个占位符到具体值得映射dict对象)作为参数调用它的 render()方法(template对象也有这个方法),则template对象递归以context对象调用其每一个node的这个render方 法,这样所有的render()输出连起来就是整个渲染好的输出文档

    2. 如何实现的具体步骤

      1. 实现编译:
        1. 扫描文本时,每当遇到一个模板tag,django以一个paser对象和tag本身的内容这2个变量作为参数调用一个python函数(编译函数),这个函数对tag的内容进行识别处理,返回一个Node对象
        2. 例如,如果写一个模板tag,{% current_time %},它以后面跟着的格式化参数来显示当前的日期和时间:
        3. <p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>
          则编译函数的解析参数"%Y-%m-%d %I:%M %p",并返回一个Node对象
          from django import template
          def do_current_time(parser, token):
          try:
              # split_contents() knows not to split quoted strings.
              tag_name, format_string = token.split_contents()
          except ValueError:
              raise template.TemplateSyntaxError, "%r tag requires a single argument" % token.contents.split()[0]
          if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
              raise template.TemplateSyntaxError, "%r tag's argument should be in quotes" % tag_name
          return CurrentTimeNode(format_string[1:-1]
        4. 上面的例子注意:
          1. parser是模板parser对象,这里没有使用到
          2. token.contents是raw文本的内容,即 : current_time "%Y-%m-%d %I:%M %p"
          3. token.split_contents()按照空格把上面的 contents分割,引号内的内容作为一个整体是不分割的,如果引号内有空格也不分割,但是另一个函数token.conetents.split() 就不管三七二十一,全部按照空格分隔,这样可能不太好,一般建议都用split_contents()比较安全
          4. 函数抛出异常template.TemplateSyntaxError,这个异常包含错误信息
          5. 这个异常使用的tag_name信息,不要硬编码tag_name到这个异常中,一般用token.contents.split()[0]这里比较安全,即使contents没有参数
          6. 这个函数返回了CurrentTimeNode对象,参数里应该包含一切这个Node对象所需要的信息,这个例子里仅仅是参数format_string :"%Y-%m-%d %I:%M %p",可以用format_string[1:-1]去掉两端的双引号
          7. 语法解析是比较低层次的,因为这样速度比较快
      2. 实现渲染:
        1. 第二步是定义一个Node的子类,它带有一个render()参数,紧接上面的编译过程,这里给出渲染的类:
        2. from django import template
          import datetime
          class CurrentTimeNode(template.Node):
              def __init__(self, format_string):
                  self.format_string = format_string
              def render(self, context):
                  return datetime.datetime.now().strftime(self.format_string)
        3. 上面的例子注意:
          1. __init__()从format_string得到参数,django模板系统总是使用__init__()函数作为参数传递入口
          2. render()类成员函数就是实际上渲染的工作函数
          3. render()函数不应该抛出异常,一般只应该静静地失败
        4. 这个编译与渲染的解耦和很有效且高效地实现了模板系统,这样这个模板系统可以服用以前的编译结果,使用多个context对象来渲染一个编译结果
      3. 自动转义(1.0新功能):
        1. 模板tag的输出并不会自动(通过auto-escape filter)转义,仍然需要注意如下
        2. 如果render()函数将结果存储在一个context变量中(而不是作为一个字符串返回)的时候,如果需要,应该小心地调用 mark_safe()函数。当这个context变量最终被渲染的时候,它先前设置的自动转义将起作用,因此那些当前不需要转义的内容应当被标记成安全 的,用mark_safe()函数
        3. 另外,如果模板tag内部自己创建了一个context来进行子渲染的时候,在那个context上设置和当前context一致的auto-escape属性:context的__init__()函数上有一个参数叫autoescape可以为这个目的设置:
        4. def render(self, context):
              t = template.loader.get_template('small_fragment.html')
              return t.render(Context({'var': obj}, autoescape=context.autoescape))
          如果忘了传递当前的context.autoescape到新的context上的话,结果将总是被自动转义,当这么模板tag在一个{%
           autoescape
           off
           %}
          
          块中的时候,
          这可能不是一个需要的行为
      4. 注册tag:
        1. 最后,用本模块的Library实例注册这个自定义的tag:
        2. register.tag('current_time', do_current_time)
        3. tag()函数有两个参数:
          1. 模板tag的名字:一个字符串,则编译函数的名字将被用作模板tag的名字
          2. 编译函数:一个python函数指针,而不是python函数名字符串
        4. 在python2.4和以上的版本中,也可以用如下修饰符:
        5. @register.tag(name="current_time")
          def do_current_time(parser, token):
              # ...
          
          @register.tag
          def shout(parser, token):
              # ...
          如果tag没有带name参数,则python函数名将用作tag名
      5. 传递模板变量到tag:
收藏到: Del.icio.us
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值