zoukankan      html  css  js  c++  java
  • 20190118 Jinja2模板详解

    为什么需要模板?

    1. 让HTML设计者和后端Python开发工作分离
    2. 减少使用PYthon的复杂程度,页面逻辑应该独立业务逻辑,这样才能开发出易于维护的程序
    3. 模板非常灵活、快速和安全,对设计者和开发者会更友好

    Python语言自带的模板

    In : from string import Template
    In : s = Template('$who likes $what')
    In : s.substitute(who='tim', what='kung pao')
    Out: 'tim likes kung pao'
    In : s = Template("$var is here but $missing is not provided")
    In : s.safe_substitute(var='tim')Out: 'timis here but $missing isnot provided'
    In : class MyTemplate(Template):
    ...: delimiter = '@' # 使用`@`为分隔符
    ...: idpattern = '[a-z]+.[a-z]+' # 符合的模式才会被替换
    ...:
    In : t = MyTemplate('@with.dot @notdoted')
    In : t.safe_substitute({'with.dot': 'replaced', 'notdoted': 'not replaced'})
    Out: 'replaced @notdoted'
    

    Jinja2特点

    1. 沙箱中执行
    2. 强大的HTML自动转移系统保护系统免受XSS攻击
    3. 模板继承
    4. 即时编译最优的Python代码
    5. 易于调式
    6. 可配置的语法

    安装Jinja2

    ❯ pip install Jinja2❯ 
    python -c 'import jinja2; print(jinja2.__version__)'2.10
    

    基本API使用

    In : from jinja2 import Template
    In : template = Template('Hello {{ name }}!')
    In : template.render(name='Xiao Ming')
    Out: u'Hello Xiao Ming!'
    
    In : from jinja2 import EnvironmentIn : env = Environment()
    In : template = env.from_string('Hello {{ name }}!')
    In : template.render(name='Xiao Ming')
    Out: u'Hello Xiao Ming!'
    ❯ echo "Hello {{ name }}" > hello.html❯ 
    touch app.py
    ❯ ipython
    In : from jinja2 import Environment, PackageLoader
    In : env = Environment(loader=PackageLoader('app', 'templates'))
    In : template = env.get_template('hello.html')
    In : template
    Out: <Template 'hello.html'>
    In : template.render(name='Geng WenHao')
    Out: u'Hello Geng WenHao'
    

    Jinja2支持多种loader

    1. FileSystemLoader
    In : from jinja2 import FileSystemLoader
    In : loader = FileSystemLoader('templates')
    In : template = Environment(loader=loader).get_template('hello.html')
    In : loader = FileSystemLoader(['/path/to/templates', '/other/path'])
    
    1. DictLoader
    In: loader = DictLoader({'hello.html': 'Hello {{ name }}'})
    
    1. 自定义Loader
    ❯ cat my_loader.py
    # coding=utf-8
    from os.path import join, exists, getmtime
    from jinja2 import BaseLoader, TemplateNotFound
    
    classMyLoader(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)
    
    

    字节码缓存 - FileSystemBytecodeCache

    from jinja2 import FileSystemBytecodeCache
    bcc = FileSystemBytecodeCache('/tmp/jinja2_cache', '%s.cache')
    

    字节码缓存 - MemcachedBytecodeCache

    from jinja2 import MemcachedBytecodeCache
    import memcache
    
    mc = memcache.Client(['127.0.0.1:11211'], debug=0)
    bxx = MemcachedBytecodeCache(mc, prefix='jinja2/bytecode/')
    

    自定义字节码缓存

    ❯ mkdir tmp # 创建一个存放字节码缓存的目录, 之后的临时文件也都放在这里面
    ❯ cat bytecode_cache.py
    # coding=utf-8
    import shutil
    from os import path
    from jinja2 import Environment, DictLoader, BytecodeCache
    
    
    class MyCache(BytecodeCache):
        def __init__(self, directory):
            self.directory = directory
    
    
    def load_bytecode(self, bucket):
        filename = path.join(self.directory, bucket.key)
        if path.exists(filename):
            with open(filename, 'rb') as f:
                bucket.load_bytecode(f)
    
    
    def dump_bytecode(self, bucket):
        filename = path.join(self.directory, bucket.key)
        with open(filename, 'wb') as f:
            bucket.write_bytecode(f)
    
    
    def clear(self):
        shutil.rmtree(self.directory)
    
    
    if __name__ == '__main__':
        loader = DictLoader({'hello.html': 'Hello {{ name }}'})
        env = Environment(loader=loader, bytecode_cache=MyCache('tmp'))
        template = env.get_template('hello.html')
        print(template.render(name='Geng WenHao'))
    
    ❯ python bytecode_cache.pyHello Xiao Ming
    ❯ ll tmptotal 4.0K-rw-r--r-- 1 dongwm staff 870 Sep 1516:349a60b6907b5908143cfea0aa8f6f88cd6b9138df
    

    自定分隔符

    In : template = Template('Hello $ name $!', variable_start_string='$', variable_end_string='$') # 现在使用`$`作为分隔符
    In : template.render(name='Geng WenHao')
    Out: u'Hello Geng WenHao!
    
    ''''
    * block_start_string:块开始标记。默认是{%。
    * block_end_string:块结束标记。默认是%}。
    * comment_start_string:注释开始标记。默认是{#。
    * comment_end_string:注释结束标记。默认是#}。
    '''
    

    沙箱

    In : from jinja2.sandbox import SandboxedEnvironment
    In : env = SandboxedEnvironment()
    In : env.from_string("{{ func.func_code }}").render(func=lambda:None)
    Out: u''
    In : env.from_string("{{ func.func_code.do_something }}").render(func=lambda:None)
    --------------------------------------------------------------------SecurityError
    

    JinJa2的基本语法

    > cat simple.html
    <!DOCTYPE html>
    <html lang="en">
        <head>
            <title>Simple Page</title>
        </head>
        <body>{# This is a Comment #}
            <ul id="navigation">
                {% for item in items %}
                    <li><a href="{{ item.href }}">{{ item['caption'] }}</a></li>
                {% endfor %}
            </ul>
            <h1>{{ title | trim }}</h1>
            <p>{{ content }}</p>
      </body>
    </html>
    
    

    空白控制

    {% for item in seq -%}
        {{ item }}
    {%- endfor %}
    
    {%- if foo -%}...{% endif %} # 有效的
    {% - if foo - %}...{% endif %} # 无效的
    

    行语句

    <ul>
    # for item in seq:
        <li>{{ item }}</li>
    # endfor
    </ul>
    
    <ul>
    {% for item in seq %}
        <li>{{ item }}</li>
    {% endfor %}
    </ul>
    
    <ul># for href, caption in [('index.html', 'Index'), ('about.html', 'About')]:
        <li><a href="{{ href }}">{{ caption }}</a></li>
    # endfor
    </ul>
    
    # for item in seq:
        <li>{{ item }}</li> ## this comment is ignored
    # endfor
    

    模板继承

    ❯ cat base.html
    <!DOCTYPE html>
    <html lang="en">
        <head>
            {% block head %}
                <link rel="stylesheet"href="style.css" />
                <title>{% block title %}{% endblock %} - My Webpage</title>
            {% endblock %}
        </head>
        <body>
            <div id="content">
                {% block content %}
                {% endblock %}
            </div>
            <div id="footer">
                {% block footer %}
                {% endblock %}
            </div>
        </body>
    </html>
    
    ❯ cat index.html
    {% extends "base.html" %}
    {% block title %}Index{% endblock %}
    {% block head %}
        {{ super() }}
        <style type="text/css">.important { color: #336699; }
        </style>
    {% endblock %}{% block content %}
    <h1>Index</h1>
    <p class="important">   
        Welcome on my awesome homepage.
    </p>
    {% endblock content %}
    

    控制结构 - for

    {% for item in items %}
    ...
    {% endfor %}
    
    <ul>
    {% for user in users %}
        <li>{{ user.username|e }}</li>
    {% else %}
        <li><em>no users found</em></li>
    {% endfor %}
    </ul>
    
    # 特殊变量
    1.loop.index:当前循环迭代的次数(从1开始)
    2.loop.index0:当前循环迭代的次数(从0开始)
    3.loop.first:如果是第一次迭代值为True
    4.loop.last:如果是最后一次迭代值为True
    5.loop.length:序列中的项目数
    

    控制结构 - 条件语句

    {% if xiaoming.is_admin %}    
        GengWenHao is a Administrator
    {% elif xiaoming.is_editor %}    
        GengWenHao is a Editor
    {% else %}    
        Unknown User
    {% endif %}
    
    {% extends layout_template if layout_template is defined else 'master.html' %}
    

    In : Template('''
    ...: {% macro hello(name) %}
    ...: Hello {{ name }}
    ...: {% endmacro %}
    ...: <p>{{ hello('world') }}</p>
    ...: ''').render()
    Out: u'
    
    <p>
     Hello world
    </p>'
    

    赋值

    In : print Template('''
    ...: {% set a = 1 %}
    ...: {% set b, c = range(2) %}
    ...: <p>{{ a }} {{ b }} {{ c }}</p>
    ...: ''').render()
    Out: u'
    
    
    <p>1 0 1</p>'
    

    include

    {% include 'header.html' %}    
        Body
    {% include 'footer.html' %}
    
    {% include "sidebar.html" ignore missing %}
    

    import

    ❯ cat macro.html
    {% macrohello(name) %}    
    Hello {{ name }}
    {% endmacro %}
    
    {% macro strftime(time, fmt='%Y-%m-%d %H:%M:%S') %}    
        {{ time.strftime(fmt) }}
    {% endmacro %}❯ 
    
    > cat hello_macro.html
    {% import 'macro.html'asmacro%}
    {% from 'macro.html' import hello as _hello, strftime %}
    
    <p>{{ macro.hello('world') }}</p>
    <p>{{ strftime(time) }}</p>
    
    In : from jinja2 import FileSystemLoader, Environment
    In : from datetime import datetime
    In : loader = FileSystemLoader('templates')
    In : template = Environment(loader=loader).get_template('hello_macro.html')
    In : template.render(time=datetime.now())
    Out:'
    
    
    <p>
     Hello world
    </p>
    <p>
     2018-09-15 23:05:19
    </p>'
    

    延伸阅读

    1. http://jinja.pocoo.org/docs/2.10/templates/#list-of-global-functions
    2. http://jinja.pocoo.org/docs/2.10/
  • 相关阅读:
    [置顶] 搭建一个流媒体服务器引子
    Exchange Server 2007 常见问题解答(6)
    [置顶] 第九周项目1
    iOS 6应用开发实战
    hdu 1722(数论)
    js二维数组排序
    HDU 4027 线段树 Can you answer these queries?
    Socket编程指南及示例程序
    Spring攻略学习笔记(2.13)解析文本消息
    线性渐变lineargradient和滤镜opacity/filter的透明效果兼容性解决方案及其RGB/RGBA与16进制转换方法
  • 原文地址:https://www.cnblogs.com/gengwenhao/p/10699610.html
Copyright © 2011-2022 走看看