编程语言
首页 > 编程语言> > python jinjia2 高级

python jinjia2 高级

作者:互联网

高层api

class jinja2.Environment([options])

Enviroment:环境,是Jinjia2的核心组件,它包含重要的共享变量,如配置、过滤器、测试、全局变量、模板加载器等。上述的使用模板加载器就是使用到了loader参数来加载我们指定的模板资源。

构造方法中的属性

    <ul>
        # for item in seq
        <li>{{ item }}</li>
        # endfor
    </ul>

    <ul>
        {% for item in seq %}
        <li>{{ item }}</li>
        {% endfor %}
    </ul>

    <ul>
        # for item in seq 
        <li>{{ item }}</li> ## test
        # endfor
    </ul>

    <ul>
        {% for item in seq %} {# test #}
        <li>{{ item }}</li>
        {% endfor %}
    </ul>

需要注意的是line_statement_prefixline_comment_prefix最好不要在同一行出现,尤其是设置的类似的时候。

    <ul>
 

        <li>1</li>
        
 

        <li>2</li>
        
 

        <li>3</li>
        

    </ul>
    <ul>
 
        <li>1</li>
        
 
        <li>2</li>
        
 
        <li>3</li>
        
    </ul>
    <ul> 
            <li>1</li>
         
            <li>2</li>
         
            <li>3</li>
         </ul>
    <ul> 
            <li>1</li>
 
            <li>2</li>
 
            <li>3</li>
 </ul>
Unix系统里,每行结尾只有“<换行>”,即"\n";Windows系统里面,每行结尾是“<回车><换行>”,即“\r\n”;Mac系统里,每行结尾是“<回车>”,即"\r";。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>

            <li>1</li>






            <li>3</li>


    </ul>
</body>

</html>


<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>

            <li>1</li>



            <li>2</li>



            <li>3</li>


    </ul>
</body>

</html>

如上述所示,少了一个换行符

方法

classjinja2.Template

核心的模板对象,由Enviroment对象产生,对于一个模板对象来说,是不可修改的。

classjinja2.environment.TemplateStream

模板流的工作方式与普通的 Python 生成器非常相似,但它可以缓冲多个项目以减少总迭代次数。 默认情况下,输出是无缓冲的,这意味着对于模板中的每条无缓冲指令,都会产生一个 unicode 字符串。如果在缓冲区大小为 5 的情况下启用缓冲,则将五个项目组合成一个新的 unicode 字符串。 如果您通过 WSGI 将大模板流式传输到客户端,这在每次迭代后刷新,这主要是有用的。

自动转义

自动转义就是自动帮你将特殊的字符替换成转义符号。HTML(或者XML, XHTML)的特殊字符有 &, >, <, “, ‘。如下

<h1>hello</h1>

当开启自动转义后,将无法正常显示标签的含义。因此,在某些情况下,我们需要关闭自动转义或者对特定的文件格式做自动转义,可以使用Environment中的autoescape自定义转义格式要求,如下只对html、html、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'])

标识符的说明

在Jinjia2中,python3以上,有效的标识符必须匹配 [a-zA-Z_][a-zA-Z0-9_]*, 也就是必须由字母、数字、下划线组成。但是对于过滤器(filters)和测试(tests)来说,过滤器和测试标识符的正则表达式是 [a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)*,相比有效标识符,多了个.

未定义类型

待更新

上下文

加载器

从类似于文件、数据库、其他资源中加载模板,并会保存在内存中,但是默认缓存有大小限制,由Environmentcache_size控制,加载器也可以自己重写,只需要继承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 open(path) as f:
            source = f.read()
        return source, path, lambda: mtime == getmtime(path)

方法

内置的加载器

1.classjinja2.FileSystemLoader(searchpath, encoding='utf-8', followlinks=False)
从文件系统加载模板路径,是文件系统加载的首选方式。推荐使用

2.classjinja2.PackageLoader(package_name, package_path='templates', encoding='utf-8')
从python的包中加载模板,此方法对于路径要求较为严苛,类似于代码中的导入

3.classjinja2.DictLoader(mapping)
从python中的字典导入,将所有的模板文件以{模板文件名称:模板文件路径}的形式存放于字典中

4.classjinja2.FunctionLoader(load_func)
从方法中加载模板,一般在方法中做判断,返回模板文件

def load_template(name):
    if name == 'index.html':
        return '...'
loader = FunctionLoader(load_template)

5.classjinja2.PrefixLoader(mapping, delimiter='/')

将不同的模板文件夹分类,添加前缀,方便后续调用模板操作。例如

loader = PrefixLoader({
    'app1':     PackageLoader('mypackage.app1'),
    'app2':     PackageLoader('mypackage.app2')
})

此时使用app1/template.html就可以获取到mypackage.app1下面的模板文件了
6.classjinja2.ChoiceLoader(loaders)
依次查找模板,直到找到存在的模板停止

loader = ChoiceLoader([
    FileSystemLoader('/path/to/user/templates'),
    FileSystemLoader('/path/to/system/templates')
])

7.classjinja2.ModuleLoader(path)
从预编译的模板里加载模板,模板可以使用compile_templates进行预编译,然后指定路径即可

字节码缓存

有利于加载模板时使用

实用工具

import pathlib
from jinja2 import FileSystemLoader, pass_environment
from markupsafe import escape

template_path = (
    pathlib.Path(__file__).parent.joinpath("template_demo").joinpath("templates")
)

env = Environment(
    trim_blocks=True, lstrip_blocks=True, loader=FileSystemLoader(template_path)
)


@pass_environment
def fun(env: Environment, val):
    print(env.autoescape)
    return val


env.filters["fun"] = fun
template = env.get_template("template2.html")
data = template.render(seq=["<h1>1<h1>", "<h2>2<h2>", "<h3>3<h3>"])
print(data)

html_path = pathlib.Path(__file__).parent.joinpath("test.html")

with open(html_path, mode="w", encoding="utf-8") as w_f:
    w_f.write(data)

False
False
False
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
         <li><h1>1<h1></li>
         <li><h2>2<h2></li>
         <li><h3>3<h3></li>
    </ul>
</body>

</html>

从结果看,默认是未开启自动转义的,因此结果的html标签是正常的,当对val添加escape之后,修改如下

@pass_environment
def fun(env: Environment, val):
    print(env.autoescape)
    return escape(val)
False
False
False
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
         <li>&lt;h1&gt;1&lt;h1&gt;</li>
         <li>&lt;h2&gt;2&lt;h2&gt;</li>
         <li>&lt;h3&gt;3&lt;h3&gt;</li>
    </ul>
</body>

</html>

结果发现,html标签被转义了

import pathlib
from jinja2 import FileSystemLoader, pass_environment
from markupsafe import Markup

template_path = (
    pathlib.Path(__file__).parent.joinpath("template_demo").joinpath("templates")
)

env = Environment(
    trim_blocks=True, lstrip_blocks=True, loader=FileSystemLoader(template_path)
)


@pass_environment
def fun(env: Environment, val):
    print(env.autoescape)
    return Markup.escape(val)


env.filters["fun"] = fun
template = env.get_template("template2.html")
data = template.render(seq=["<h1>1<h1>", "<h2>2<h2>", "<h3>3<h3>"])
print(data)

html_path = pathlib.Path(__file__).parent.joinpath("test.html")

with open(html_path, mode="w", encoding="utf-8") as w_f:
    w_f.write(data)

异常

自定义过滤器

自定义过滤器只是常规的 Python 函数,过滤器左边作为第一个参数,其余的参数作 为额外的参数或关键字参数传递到过滤器。
例如在过滤器 {{ 42|myfilter(23) }} 中,函数被以 myfilter(42, 23) 调用, 注册过滤器一般有两种情况
**1.不依赖于上下文及环境
例如存在如下模板文件, fun为我们自定义的过滤器

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
        {% for item in seq %} {# test #}
        <li>{{ item|fun() }}</li>
        {% endfor %}
    </ul>
</body>

</html>

python代码
我们设置了过滤器返回值大于3的值

import pathlib
from jinja2 import FileSystemLoader


def fun(val):
    return val > 3


template_path = (
    pathlib.Path(__file__).parent.joinpath("template_demo").joinpath("templates")
)

env = Environment(
    trim_blocks=True, lstrip_blocks=True, loader=FileSystemLoader(template_path)
)
env.filters["fun"] = fun
template = env.get_template("template2.html")
data = template.render(seq=[1, 2, 3])
print(data)

结果

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <ul>
         <li>False</li>
         <li>False</li>
         <li>False</li>
    </ul>
</body>

</html>

2.依赖上下文环境,需要上下文环境相关参数,
contextfilter是上下文过滤器,传入的第一个参数为上下文context
evalcontextfilter是环境过滤器,传入的第一个参数为eval_context
environmentfilter:是求值上下文过滤器,传入的第一个参数为environment
需要注意,python3.0之后,
pass_context 替代 contextfunctioncontextfilter.
pass_eval_context 替代 evalcontextfunctionevalcontextfilter
pass_environment 替代 environmentfunctionenvironmentfilter.
例如在设置自动转义的情况下不希望将部分标签进行转义, 使用方法如下:

import pathlib
from jinja2 import FileSystemLoader, pass_environment, pass_eval_context, pass_context


template_path = (
    pathlib.Path(__file__).parent.joinpath("template_demo").joinpath("templates")
)

env = Environment(
    trim_blocks=True, lstrip_blocks=True, loader=FileSystemLoader(template_path)
)


@pass_environment
def fun(env: Environment, val):
    print(env.block_end_string)
    print(env.filters)
    return val > 3


env.filters["fun"] = fun
template = env.get_template("template2.html")
data = template.render(seq=[1, 2, 3])
print(data)

求值上下文

求值上下文(缩写为 eval context 或 eval ctx ),2,4版本添加,就是上述自定义过滤器的evalcontextfilter,它目前主要使用于启用或关闭自动转义,官方推荐使用求值上下文来获取转义状态。

from jinja2.nodes import EvalContext

@pass_eval_context
def fun(eval_ctx: EvalContext, val):
    return eval_ctx.autoescape

自定义测试

与自定义过滤器类似,也是通过注册的方式,不过是tests关键字,一般用于模板的类型与一致性检查

标签:None,env,python,高级,jinjia2,template,path,模板,加载
来源: https://www.cnblogs.com/xy-bot/p/16518246.html