[python][flask]Jinja模板入门

博客 动态
0 254
优雅殿下
优雅殿下 2022-04-11 08:57:59
悬赏:0 积分 收藏

[python][flask] Jinja 模板入门


目录
  • 1、快速体验
  • 2、Flask 最小 DEMO
  • 3、模板继承
  • 4、Super Blocks
  • 5、Macros
  • 6、自定义过滤器
  • 7、结论
  • 参考链接


Flask 和 Django 附带了强大的 Jinja 模板语言。

对于之前没有接触过模板语言的人来说,这类语言基本上就是包含一些变量,当准备渲染呈现 HTML 时,它们会被实际的值替换。

这些变量放在标记或分隔符之前。例如:Jinja 模板使用 {% ... %} 表示循环,{{ ... }} 表示一个表达式运算结果返回。

Jinja 模板其实是 html 文件。一般情况下放在 Flask 工程的 /templates 目录下


1、快速体验

跑下面的各种 demo 之前,确保你已经安装了 Jinja (pip install jinja2)

>>> from jinja2 import Template>>> t = Template("Hello {{ something }}!")>>> t.render(something="World")u'Hello World!'>>> t = Template("My favorite numbers: {% for n in range(1,10) %}{{n}} " "{% endfor %}")>>> t.render()u'My favorite numbers: 1 2 3 4 5 6 7 8 9 '

这个 demo 展示了模板中的变量(表达式)是如何最终被替换和渲染的。


2、Flask 最小 DEMO

整个的参考代码可以在这里获得:HERE

不过博主建议按照下面步骤一步步来:

1)安装 flask

?  pip install flask

2)创建工程目录结构:

?  mkdir flask_example?  cd flask_example ?  mkdir templates?  cd ..?  touch run.py?  touch requirements.txt

3)编写 run.py

from flask import Flask, render_templateapp = Flask(__name__)@app.route("/")def template_test():    return render_template('template.html', my_string="Wheeeee!", my_list=[0,1,2,3,4,5])if __name__ == '__main__':    app.run(debug=True)

这里,我们创建了一个 / 路由,当我们访问服务器根路由时,会通过 render_template 将 template.html 渲染,其中 my_string 和 my_list 就是准备传给模板的实际的值。


4)编写 template.html 模板

在 templates 目录下,创建一个 template.html:

<!DOCTYPE html><html>  <head>    <title>Flask Template Example</title>    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen">    <style type="text/css">      .container {        max-width: 500px;        padding-top: 100px;      }    </style>  </head>  <body>    <div >      <p>My string: {{my_string}}</p>      <p>Value from the list: {{my_list[3]}}</p>      <p>Loop through the list:</p>      <ul>        {% for n in my_list %}        <li>{{n}}</li>        {% endfor %}      </ul>    </div>    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>    <script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>  </body></html>

5)运行观察效果

?  python run.py

效果如下:

可以看到,将模板中的 my_string、my_list[3] 替换掉了,并且用 for 循环语句,生成了一个 list。


3、模板继承

模板通常利用继承,继承包括定义所有后续子模板基本结构的单个基础模板。您可以使用标记 {% extends %} 和 {% block %} 来实现继承。

这样做的用例很简单:随着应用程序的增长,以及您继续添加新模板,您将需要保持公共代码(如HTML导航栏、Javascript库、CSS样式表等)同步,这可能需要大量工作。使用继承,我们可以将这些公共部分移动到父/基模板,这样我们就可以创建或编辑这样的代码一次,所有子模板都将继承该代码。

注意:您应该总是尽可能多地向基本模板添加重复代码,以节省将来的时间,这将远远超过初始时间投资。

让我们给我们的 DEMO 增加模板:

1)创建基础模板(保存为 layout.html)

<!DOCTYPE html><html>  <head>    <title>Flask Template Example</title>    <meta name="viewport" content="width=device-width, initial-scale=1.0">    <link href="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen">    <style type="text/css">      .container {        max-width: 500px;        padding-top: 100px;      }      h2 {color: red;}    </style>  </head>  <body>    <div >      <h2>This is part of my base template</h2>      <br>      {% block content %}{% endblock %}      <br>      <h2>This is part of my base template</h2>    </div>    <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script>    <script src="http://netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>  </body></html>

你注意到 {%block%} 标记了吗?这定义了子模板可以填充的块或区域。此外,也可实现覆盖的作用。


2)用模板更新 template.html:

{% extends "layout.html" %}{% block content %}  <h3> This is the start of my child template</h3>  <br>  <p>My string: {{my_string}}</p>  <p>Value from the list: {{my_list[3]}}</p>  <p>Loop through the list:</p>  <ul>    {% for n in my_list %}    <li>{{n}}</li>    {% endfor %}  </ul>  <h3> This is the end of my child template</h3>{% endblock %}

这样 layout.html 模板中的 content 块就会被 template.html 中的新定义给替换掉,最终效果如下:


那么,我们就可以通过修改 layout.html 给其添加通用导航栏了:(将下列代码插入到 layout.html 的 <body> 标签之后)

<nav  role="navigation">  <div >    <div >      <button type="button"  data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">        <span >Toggle navigation</span>        <span ></span>        <span ></span>        <span ></span>      </button>      <a  href="/">Jinja!</a>    </div>    <div  id="bs-example-navbar-collapse-1">      <ul >        <li ><a href="#">Link</a></li>        <li><a href="#">Link</a></li>      </ul>      <form  role="search">        <div >          <input type="text"  placeholder="Search">        </div>        <button type="submit" >Submit</button>      </form>      <ul >        <li><a href="#">Link</a></li>        <li >          <a href="#"  data-toggle="dropdown">Dropdown <b ></b></a>          <ul >            <li><a href="#">Action</a></li>            <li><a href="#">Another action</a></li>            <li><a href="#">Something else here</a></li>            <li ></li>            <li><a href="#">Separated link</a></li>          </ul>        </li>      </ul>    </div><!-- /.navbar-collapse -->  </div><!-- /.container-fluid --></nav>

现在,从基础扩展的每个子模板都将具有相同的导航栏。借用Java哲学的一句话:"Write once, use anywhere."


4、Super Blocks

如果需要从基础模板渲染块,使用 super block:

{{ super() }}

给基础模板增加一个页脚:

<body><div > ...  <h2>This is part of my base template</h2>  <br>  <div >    {% block footer %}      Watch! This will be added to my base and child templates using the super powerful super block!      <br>      <br>      <br>    {% endblock %}  </div></div>...

此时,我们可以给 template.html 增加 super block,从而实现子模板复用父模板中的块:

{% extends "layout.html" %}{% block content %}  <h3> This is the start of my child template</h3>  <br>  <p>My string: {{my_string}}</p>  <p>Value from the list: {{my_list[3]}}</p>  <p>Loop through the list:</p>  <ul>    {% for n in my_list %}    <li>{{n}}</li>    {% endfor %}  </ul>  <h3> This is the end of my child template</h3>  {% block footer %}  {{super()}}  {% endblock %}{% endblock %}

效果如下:


super block 用于模块共享父模块的 block,当然还有一些高级玩法,比如下面的例子:

父模板:

{% block heading %}  <h1>{% block page %}{% endblock %} - Flask Super Example</h1>{% endblock %}

子模板:

{% block page %}Home{% endblock %}{% block heading %}  {{ super() }}{% endblock %}

这样当访问子模块时,会拼接一个 <h1>Home - Flask Super Example</h1> 字段。发现没,我们通过这样的方法,实现了标题的继承(有一定的继承,也有一定的子模块自己的信息)。

回归正轨,对于更新标题,我们这里这样设计(修改 template.html 中的两行代码)

{% block title %}{{title}}{% endblock %}...{% block page %}{{title}}{% endblock %}

这样我们可以通过 python 进来直接修改标题了(修改 run.py):

@app.route("/")def template_test():    return render_template(        'template.html', my_string="Wheeeee!",         my_list=[0,1,2,3,4,5], title="Home")

5、Macros

在 Jinja 中,我们可以使用宏来抽象常用的代码段,这些代码段被反复使用以避免重复。例如,通常会在导航栏上突出显示当前页面的链接(活动链接)。否则,我们必须使用 if/elif/else 语句来确定活动链接。使用宏,我们可以将这些代码抽象成一个单独的文件。

新增一个 macros.html 文件:

{% macro nav_link(endpoint, name) %}{% if request.endpoint.endswith(endpoint) %}  <li ><a href="{{ url_for(endpoint) }}">{{name}}</a></li>{% else %}  <li><a href="{{ url_for(endpoint) }}">{{name}}</a></li>{% endif %}{% endmacro %}

这里,我们使用了 Flask 的 request object(Jinja 的默认一部分),用来检查请求端点,然后将活动 class 分配给该端点。

使用基础模板中的nav navbar nav类更新无序列表:

<ul >  {{ nav_link('home', 'Home') }}  {{ nav_link('about', 'About') }}  {{ nav_link('contact', 'Contact Us') }}</ul>

此外,请确保在模板顶部添加导入:{% from "macros.html" import nav_link with context %}

最后,让我们向控制器添加三个新端点:

@app.route("/home")def home():    return render_template(        'template.html', my_string="Wheeeee!",         my_list=[0,1,2,3,4,5], title="Home")@app.route("/about")def about():    return render_template(        'template.html', my_string="Wheeeee!",         my_list=[0,1,2,3,4,5], title="About")@app.route("/contact")def contact():    return render_template(        'template.html', my_string="Wheeeee!",         my_list=[0,1,2,3,4,5], title="Contact Us")

刷新页面。测试顶部的链接。当前页面是否突出显示?(每次点击 Home, About, Contact Us,浏览器会自动跳转到对应的 url,并加载页面)


6、自定义过滤器

Jinja 使用过滤器修改变量,主要用于格式化目的。

这有个例子;

{{ num | round }}

这将使 num 变量四舍五入。因此,如果我们将参数 num=46.99 传递到模板中,那么将输出47.0。(把大括号中的语句当做 shell,就明白了,竖线是传递作用,round是个过滤器,这里是所有的过滤器)

再来个例子:

{{ list|join(', ') }}

可以给 list 数组中的变量加个逗号。

其实,除了自带的过滤器,我们也可以自定义:

1)在 run.py 的所有函数前增加 app = Flask(__name__) 用于创建一个 app
2)增加一个 datetimefilter 函数,并将其注册到 app 的过滤器

@app.template_filter() # 声明,这是个过滤器def datetimefilter(value, format='%Y/%m/%d %H:%M'):    """Convert a datetime to a different format."""    return value.strftime(format)app.jinja_env.filters['datetimefilter'] = datetimefilter

3)这样,我们在子模板中插入如下代码:

<h4>Current date/time: {{ current_time | datetimefilter }}</h4>

4)最后,只要在 python 中将时间传入模板即可:

current_time = datetime.datetime.now()

5)效果如下:


7、结论

这样,就送大家快速入门了 Jinja,源码:https://github.com/mjhea0/thinkful-mentor/tree/master/python/jinja/flask_example


参考链接

[1]. 本文源码
[2]. Primer on Jinja Templating(本文翻译并参考这篇)
[3]. Flask 官方文档
[4]. 真正搞明白Python中Django和Flask框架的区别
[5]. Flask 主页
[6]. 一个 Soft UI Dashboard - Free Jinja Template
[7]. Appseed 这个网站有很多 Flask 模板
[8]. Nginx 服务器 SSL 证书安装部署
[9]. python django web 开发 —— 15分钟送到会用(只能送你到这了)



: 在学习 Django 和 Flask 等 Python 的服务器框架时,都需要了解模板的概念,这篇能够快速带你入门...

posted @ 2022-04-11 08:27 beautifulzzzz 阅读(0) 评论(1) 编辑 收藏 举报
回帖
    优雅殿下

    优雅殿下 (王者 段位)

    2018 积分 (2)粉丝 (47)源码

    小小码农,大大世界

     

    温馨提示

    亦奇源码

    最新会员