欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Flask-jinja2学习(上)

程序员文章站 2022-06-17 15:54:33
...

jinja2的相关知识点


jinja2是python的一个web库,旨在灵活,快速和安全,可以简化python的html语法。

基本语法

  • 标记块开头的字符串 {%
  • 标记块结束的字符串 %}
  • 标记print语句开始的字符串 {{
  • 标记print语句结束的字符串 }}
  • 标记注释开头的字符串 {#
  • 标记注释结尾的字符串 #}

表达式种类

  • 最常用的变量,由Flask渲染模板时传过来,类似于 name
  • 任意一种python基础类型,例如{{ “hello” }},还有列表,元组,字典等等。
  • 运算。包括算数运算,比较运算,逻辑运算 {{False and True}}
  • 过滤器 “|” 和测试器 “is”
  • 函数调用,如{{ current-time() }},数组下标操作,{{ arr[1] }}
  • ‘in’ 操作符,如{{ 1 in [1,2,3] }}
  • 字符串连接符‘~’,和python里的‘+’一样。如{{ ‘hello’name‘!’ }}
  • ‘ if ’关键字,如{{ hi,%s %name if name }},这里的if不是控制语句

for 循环和 if else

<dl>
    {% for user in users if not user.hidden %}
        {% if loop.first %}
            <div>User List:</div>
        {% endif %}
        <div class="{{ loop.cycle('odd','even')}}">
            <dt>User No.{{loop.index}}</dt>
            <dd>{{ user.name }}</dd>
        </div>
        {% if loop.last %}
            <div>Total Users: {{ loop.length }}</div>
        {% endif %}
    {% else %}
        <div>No users found</div>
    {% endfor %}
</dl>

循环内置变量loop

  • loop.index 循环迭代计数(从1开始)
  • loop.index0 循环迭代计数(从0开始)
  • loop.revindex 循环迭代倒序计数(从len开始,到1结束)
  • loop.revindex0 循环迭代倒序计数(从len开始,到0结束)
  • loop.first 是否为循环第一个元素
  • loop.length 循环序列中的元素长度
  • loop.cycle 在给定的序列中循环
  • loop.depth 当前循环在递归的层级

忽略模板写法

<dl>
    <dl>忽略模板语法</dl>
    {% raw %}
        <ul>
            {% for item in items %}
            <li>{{ item }}</li>
            {% endfor %}
        </ul>
    {% endraw %}
</dl>

自动转义和给变量赋值

{% autoescape false %}
    <h1>Hello {{ name }}!</h1>
{% endautoescape %}
{% set items=[[1,2],[3,4,5]] %}
{{ items }}

with语句

<div>
    {% with foo =1 %}
        {% set bar =2 %}
        {{ foo + bar }}
    {% endwith %}
</div>
<div>
    {% with arr = ['Sunny','Rainy'] %}
        {{ arr }}
        {% do arr.append('ltf') %}
        {{ arr }}
    {% endwith %}
</div>

do 语法需要导入外部扩展

app.jinja_env.add_extension(‘jinja2.ext.do’)


上下文环境

Flask每个请求都有生命周期,在生命周期内请求有其上下文环境Request Context。作为在请求中渲染的模板,自然也在请求的生命周期内,所以Flask应用中的模板可以使用到请求上下文中的环境变量,及一些辅助函数。本文就会介绍下这些变量和函数。

请求对象request

request对象可以用来获取请求的方法”request.method”,表单”request.form”,请求的参数”request.args”,请求地址”request.url”等。它本身是一个字典。在模板中,你一样可以获取这些内容,只要用表达式符号”{{ }}”括起来即可。

会话对象session

session对象可以用来获取当前会话中保存的状态,它本身是一个字典。在模板中,你可以用表达式符号”{{ }}”来获取这个对象

全局对象g

全局变量g,用来保存请求中会用到全局内容,比如数据库连接。模板中也可以访问。

Flask配置对象config

导入的配置信息,就保存在”app.config”对象中。这个配置对象在模板中也可以访问。

url_for()函数

url_for()函数可以用来快速获取及构建URL,Flask也将此函数引入到了模板中,比如下面的代码,就可以获取静态目录下的”style.css”文件。

主程序

#加载扩展
app.jinja_env.add_extension('jinja2.ext.do')
app.secret_key = '123456'

@app.route('/')
def index():
    session['user'] = 'guest'
    g.db = 'mysql'
    return render_template('main.html')

main.html文件

<dl>
    <div>
    <p>{{ "请求的url为:"~request.url }}</p>
    <p>{{ "session保存的用户为:"+session.user }}</p>
    <p>DB数据库: {{ g.db}}</p>
    <p>Host配置:{{ config }}</p>
    </div>
</dl>
<dl>
    <div class="odd">

    </div>
</dl>

style.css文件

.odd {
    background-color: #BDF;
    width: 200px;
    height: 200px;
  }

自定义变量和函数

除了Flask提供的标准上下文变量和函数,我们还可以自己定义。

@app.context_processor
def appinfo():
    return dict(appname=current_app.name)
@app.context_processor
def get_current_time():
    def get_time(timeFormat="%b %d, %Y - %H:%M:%S"):
        return time.strftime(timeFormat)
    return dict(current_time=get_time)

函数用”@app.context_processor”装饰器修饰,它是一个上下文处理器,它的作用是在模板被渲染前运行其所修饰的函数,并将函数返回的字典导入到模板上下文环境中,与模板上下文合并。然后,在模板中”appname”就如同上节介绍的”request”, “session”一样,成为了可访问的上下文对象。

同理我们可以自定义上下文函数,只需将上例中返回字典的属性指向一个函数即可

<div>
    <p>当前 App is: {{ appname }}</p>
    <p>当前 Time is: {{ current_time() }}</p>
    <p>当前 Day is: {{ current_time("%Y-%m-%d") }}</p>
</div>

内置过滤器

字符串操作
    {{ '字符串操作....' }}
    {# 单词首字母大写 #}
    <p>{{ 'hello' | capitalize }}</p>

    {# 单词全小写 #}
    <p>{{ 'XML' | lower }}</p>

    {# 去除字符串前后的空白字符 #}
    <p>{{ '  hello  ' | trim }}</p>

    {# 字符串反转,返回"olleh" #}
    <p>{{ 'hello' | reverse }}</p>

    {# 格式化输出,返回"Number is 2" #}
    <p>{{ '%s is %d' | format("Number", 2) }}</p>

    {# 关闭HTML自动转义 #}
    <p>{{ '<em>name</em>' | safe }}</p>

    {% autoescape false %}
        {# HTML转义,即使autoescape关了也转义,可以缩写为e #}
        <p>{{ '<em>name</em>' | escape }}</p>
    {% endautoescape %}
数值操作
    {{ '数值操作...' }}
    {# 四舍五入取整,返回13.0 #}
    <p>{{ 12.8888 | round }}</p>

    {# 向下截取到小数点后2位,返回12.88 #}
    <p>{{ 12.8888 | round(2, 'floor') }}</p>

    {# 绝对值,返回12 #}
    <p>{{ -12 | abs }}</p>
列表操作
    {{ '列表操作...' }}
    {# 取第一个元素 #}
    <p>{{ [1,2,3,4,5] | first }}</p>

    {# 取最后一个元素 #}
    <p>{{ [1,2,3,4,5] | last }}</p>

    {# 返回列表长度,可以写为count #}
    <p>{{ [1,2,3,4,5] | length }}</p>

    {# 列表求和 #}
    <p>{{ [1,2,3,4,5] | sum }}</p>

    {# 列表排序,默认为升序 #}
    <p>{{ [3,2,1,5,4] | sort }}</p>

    {# 合并为字符串,返回"1 | 2 | 3 | 4 | 5" #}
    <p>{{ [1,2,3,4,5] | join('--') }}</p>

    {# 列表中所有元素都全大写。这里可以用upper,lower,但capitalize无效 #}
    <p>{{ ['tom','bob','ada'] | upper }}</p>
字典操作
    {{ '字典列表操作...' }}
    {% set users=[{'name':'Tom','gender':'M','age':20},
                  {'name':'John','gender':'M','age':18},
                  {'name':'Mary','gender':'F','age':24},
                  {'name':'Bob','gender':'M','age':31},
                  {'name':'Lisa','gender':'F','age':19}]
    %}

    <div>{{ users }}</div>

    {# 按指定字段排序,这里设reverse为true使其按降序排 #}
    <ul>
    {% for user in users | sort(attribute='age', reverse=true) %}
         <li>{{ user.name }}, {{ user.age }}</li>
    {% endfor %}
    </ul>

    {# 列表分组,每组是一个子列表,组名就是分组项的值 #}
    <ul>
    {% for group in users|groupby('gender') %}
        <li>{{ group.grouper }}<ul>
        {% for user in group.list %}
            <li>{{ user.name }}</li>
        {% endfor %}</ul></li>
    {% endfor %}
    </ul>

    {# 取字典中的某一项组成列表,再将其连接起来 #}
    <p>{{ users | map(attribute='name') | join(', ') }}</p>
语句块过滤
    {% filter upper %}
        This is a Flask Jinja2 introduction.
    {% endfilter %}

自定义过滤器

两种写法

  • 不用装饰器
def double_step_filter(l):
    return l[::2]

app.add_template_filter(double_step_filter, 'double_step')
  • 使用装饰器
@app.template_filter('sub')
def sub(l, start, end):
    return l[start:end]

输出…

    {# 返回[1,3,5] #}
    <p>{{ [1,2,3,4,5] | double_step }}</p>

    {# 返回[2,3,4] #}
    <p>{{ [1,2,3,4,5] | sub(1,4) }}</p>

内置测试器

显然测试器本质上也是一个函数,它的第一个参数就是待测试的变量,在模板中使用时可以省略去。如果它有第二个参数,模板中就必须传进去。测试器函数返回的必须是一个布尔值,这样才可以用来给if语句作判断。

    {% set name = 'Ltf' %}
        <p>{{ name }}</p>
    {# 检查变量是否被定义,也可以用undefined检查是否未被定义 #}
    {% if name is defined %}
        <p>Name is: {{ name }}</p>
    {% endif %}

    {# 检查是否所有字符都是大写 #}
    {% if name is upper %}
        <h2>"{{ name }}" are all upper case.</h2>
    {% endif %}

    {# 检查变量是否为空 #}
    {% if name is none %}
        <h2>Variable is none.</h2>
    {% endif %}

    {# 检查变量是否为字符串,也可以用number检查是否为数值 #}
    {% if name is string %}
        <h2>{{ name }} is a string.</h2>
    {% endif %}

    {# 检查数值是否是偶数,也可以用odd检查是否为奇数 #}
    {% if 2 is even %}
        <h2>Variable is an even number.</h2>
    {% endif %}

    {# 检查变量是否可被迭代循环,也可以用sequence检查是否是序列 #}
    {% if [1,2,3] is iterable %}
        <h2>Variable is iterable.</h2>
    {% endif %}

    {# 检查变量是否是字典 #}
    {% if {'name':'test'} is mapping %}
        <h2>Variable is dict.</h2>
    {% endif %}

自定义测试器

和自定义过滤器的写法一样

  • 无装饰器
import re
def has_number(str):
    return re.match(r'.*\d+', str)
app.add_template_test(has_number,'contain_number')
  • 有装饰器
@app.template_test('end_with')
def end_with(str, suffix):
    return str.lower().endswith(suffix.lower())
  • 模板语句
    {% if name is contain_number %}
        <h2>"{{ name }}" contains number.</h2>
    {% endif %}

    {% if name is end_with "me" %}
        <h2>"{{ name }}" ends with "me".</h2>
    {% endif %}

Github地址

相关标签: jinja2