One - One Code All

Blog Content

python中的jinja2模板

Python   2019-03-17 22:47:52

API

基础

Jinja2使用一个中心对象叫模板环境Environment,用它来存储陪着和全局对象, 然后使用它从文件或其他地方加载模板。就算刚刚的Template例子,一个Environment对象也被隐式的创建了。


大多数框架会在程序启动时创建一个Environment对象,用它来加载模板。


最简单的陪着Jinja2和加载模板的方式类似下面:

from jinja2 import Environment, PackageLoader
env = Environment(loader=PackageLoader('yourapp', 'templates'))
template = env.get_template('mytemplate.html')
print(template.render(the='variables', go='here'))

它会创建一个Environment,使用了默认配置和一个在yourapp包的templates文件夹下面搜索模板的加载器。 你还可以使用其他的加载器,或者自定义加载器,来从数据库或其他地方加载模板。


要想加载到一个模板,只需使用get_template()方法


#### Unicode Jinja2内部使用Unicode,所以传给render方法的参数必须是unicode对象,另外换行符是unix的’\n’, 最好在每个python模块第一行添加


# -*- coding: utf-8 -*-

Jinja2的模板默认编码是utf-8,一些库会严格检查str类型比如datetime.strftime,它不接受unicode参数。 所以Jinja2对于ascii字符串返回str,其他的返回unicode,比如:


>>> m = Template(u"@% set a, b = 'foo', 'föö' %@").module

>>> m.a

'foo'

>>> m.b

u'f\xf6\xf6'

自动转换

推荐的做法是开启 Autoescape Extension扩展,下面是一个推荐的启动配置方案,对于.html,.htm和.xml的模板开启自动转换, 对于其他的禁止自动转换:

def guess_autoescape(template_name):
    if template_name is None or '.' not in template_name:
        return False
    ext = template_name.rsplit('.', 1)[1]
    return ext in ('html', 'htm', 'xml')

env = Environment(autoescape=guess_autoescape,
                  loader=PackageLoader('mypackage'),
                  extensions=['jinja2.ext.autoescape'])


加载器

加载器用来某个源比如文件来加载模板。Environment对象会将编译后的模块放到内存中, 类似于python中的sys.modules,但是不同之处在于如果模板更改了它会自动查询加载。


所有加载器都继承自BaseLoader,如果你想定义自己的加载器,就写个子类,重写它的get_source方法即可。 一个基本的从文件加载模板的加载器像下面这样:

from jinja2 import BaseLoader, TemplateNotFound
from os.path import join, exists, getmtime

class MyLoader(BaseLoader):

    def __init__(self, path):
        self.path = path

    def get_source(self, environment, template):
        path = join(self.path, template)
        if not exists(path):
            raise TemplateNotFound(template)
        mtime = getmtime(path)
        with file(path) as f:
            source = f.read().decode('utf-8')
        return source, path, lambda: mtime == getmtime(path)

内置的一些加载器:


jinja2.FileSystemLoader(searchpath, encoding=’utf-8’, followlinks=False) #文件系统

jinja2.PackageLoader(package_name, package_path=’templates’, encoding=’utf-8’) #包

jinja2.DictLoader(mapping) #字典,没啥用

jinja2.FunctionLoader(load_func) #通过一个函数来加载

jinja2.PrefixLoader(mapping, delimiter=’/‘) #有前缀的

jinja2.ChoiceLoader(loaders) #多个加载器,找到第一个匹配

jinja2.ModuleLoader(path) #预编译好的模块

自定义过滤器

@% raw %@@@ 42|myfilter(23) @@@% endraw %@会被myfilter(42, 23)调用,一个例子


def datetimeformat(value, format='%H:%M / %d-%m-%Y'):

    return value.strftime(format)

然后注册到环境中


environment.filters['datetimeformat'] = datetimeformat

模板中使用:


written on: @@ article.pub_date|datetimeformat @@

publication date: @@ article.pub_date|datetimeformat('%d-%m-%Y') @@

还能给过滤器传入当前模板的context或environment, 所以就有了environmentfilter(), contextfilter() 和evalcontextfilter()三个装饰器。


下面是一个简单例子,将所有文本换行符转换为html换行符,文本段落转换我html段落。如果启动自动转换,返回安全的html字符串:

import re
from jinja2 import evalcontextfilter, Markup, escape

_paragraph_re = re.compile(r'(?:\r\n|\r|\n){2,}')

@evalcontextfilter
def nl2br(eval_ctx, value):
    result = u'\n\n'.join(u'

%s

' % p.replace('\n', Markup('
\n'))                           for p in _paragraph_re.split(escape(value)))     if eval_ctx.autoescape:         result = Markup(result)     return result

模板语法

介绍完API后,开始介绍模板设计语法


基础

下面是一个典型的模板:




    My Webpage


    
    @% for item in navigation %@
        
  • @@ item.caption @@
  •     @% endfor %@          

    My Webpage

        @@ a_variable @@

    默认的语法配置是这样的,你可以自己自定义:


    * @% raw %@@% ... %@@% endraw %@ 这个是语句

    * @% raw %@@@ ... @@@% endraw %@ 这个是表达式,打印模板输出

    * @% raw %@@% endraw %@ 这个是注释部分,不会输出

    * #  ... #  这个是行语句

    变量

    两种访问方式:


    @@ foo.bar @@

    @@ foo['bar'] @@


    # 过滤器

    @@ name|striptags|title @@


    # 测试

    @% if loop.index is divisibleby(3) %@

    空行控制,如果trim_blocks 和 lstrip_blocks都启用,那么模板自己的控制块行将不输出。


    行语句

    下面等价

      # for item in seq     
    • @@ item @@
    • # endfor
      @% for item in seq %@     
    • @@ item @@
    • @% endfor %@

    模板继承

    一个基础模板

    
    
    
        @% block head %@
        
        @% block title %@@% endblock %@ - My Webpage
        @% endblock %@
    
    
        @% block content %@@% endblock %@
                 @% block footer %@         © Copyright 2008 by you.         @% endblock %@     

    一个子模板继承上面的基础模板

    @% extends "base.html" %@
    @% block title %@Index@% endblock %@
    @% block head %@
        @@ super() @@
        
            .important { color: #336699; }
        
    @% endblock %@
    @% block content %@
        

    Index

        

          Welcome to my awesome homepage.     

    @% endblock %@

    还能指定模板名字,更加具有可读性

    @% block sidebar %@
        @% block inner_sidebar %@
            ...
        @% endblock inner_sidebar %@
    @% endblock sidebar %@

    字符转换

    可自动转换html字符,也可以手动转换


    @@ user.username|e @@

    当使用自动转换时,所有的会被转换,除非你声明它是安全的。有两种方式声明安全:


    context字典中指定MarkupSafe.Markup,

    模板使用 |safe过滤器

    流程控制语句

    列表循环

    Members

    @% for user in users %@     @%- if loop.index is even %@@% continue %@@% endif %@     ... @% endfor %@

    key-value形式的循环:

    @% for key, value in my_dict.iteritems() %@     
    @@ key|e @@
        
    @@ value|e @@
    @% endfor %@

    if判断

    @% if kenny.sick %@
        Kenny is sick.
    @% elif kenny.dead %@
        You killed Kenny!  You bastard!!!
    @% else %@
        Kenny looks okay --- so far
    @% endif %@

    赋值语句


    @% set navigation = [('index.html', 'Index'), ('about.html', 'About')] %@

    @% set key, value = call_something() %@


    块赋值


    @% set navigation %@

       

  • Index

       

  • Downloads

    @% endset %@

    包含模板


    @% include 'header.html' %@

    @% include "sidebar.html" ignore missing %@

    @% include "sidebar.html" ignore missing with context %@

    @% include "sidebar.html" ignore missing without context %@

        Body

    @% include 'footer.html' %@

    i18n

    国际化例子


    @% trans user=user.username %@Hello @@ user @@!@% endtrans %@

    @@ _('Hello %(user)s!')|format(user=user.username) @@

    临时指定autoescape


    @% autoescape true %@

        Autoescaping is active within this block

    @% endautoescape %@


    @% autoescape false %@

        Autoescaping is inactive within this block

    @% endautoescape %@

    jinja2扩展

    添加扩展


    jinja_env = Environment(extensions=['jinja2.ext.i18n'])

    FAQ

    参考 http://jinja.pocoo.org/docs/dev/faq/



    上一篇:python使用JiaJa2通过模板生成文本文件
    下一篇:python中jinja模板字典传参数
  • The minute you think of giving up, think of the reason why you held on so long.