Flask中的Jinja2模板使用
来源:互联网 发布:手机淘宝卖家怎么激活 编辑:程序博客网 时间:2024/05/17 17:43
模板
@(Flask)
视图函数
作用:生成请求的响应。
一般情况下,请求会改变程序的状态,这种改变相应的需要在视图函数中产生。
两种逻辑的处理
- 业务逻辑
- 表现逻辑
两种逻辑不分离将会使得代码难以理解和维护。
Jinja2模板引擎
模板是包含响应文本的文件。
动态部分用占位变量表示,具体的值在请求的上下文中才能知道。
渲染:使用真实值替代变量,返回最终的响应字符串。
Flask用的是强大的Jinja2模板引擎。
最简单的模板
- 只包含响应文本的文件。
#templates/index.html : Jinja2模板<h1>Hello World!</h1>
- 添加动态变量
#templates/index.html : Jinja2模板<h1>Hello,{{ name }}!</h1>
可以看到:Jinja2模板的动态部分的替代和视图函数中的不同。
#视图函数return '<h1>Hello, %s!</h1>' %name#Jinja2模板<h1>Hello,{{ name }}!</h1>
渲染模板
在程序中新建templates文件夹。
新建模板(xxx.html文档)
#index.html<h1>Hello World!</h1>#user.html<h1>Hello, {{ name }}!</h1>
在hello.py中渲染:
#!/usr/bin/python# coding=utf-8from flask import Flask, render_templatefrom flask.ext.script import Managerapp = Flask(__name__)manager = Manager(app)@app.route('/')def index(): return render_template('index.html')@app.route('/user/<name>')def user(name): return render_template('user.html',name=name)if __name__ == '__main__': manager.run() #服务器运行要依赖manager来管理,有了新的boss
注意引入render_template
包,然后视图函数的返回值用render_template()
函数来渲染模板,看到渲染时动态传入参数的方法。
render_template()函数
第一个参数是模板的文件名,随后参数都是键值对。
name=name这个语法,左边的是模板中的占位变量,右边的是传入参数。
模板变量
此类结构:{{ name }}
是特殊的占位符,告诉模板引擎这个位置的值从渲染模板时说过的数据中获取。
Jinja2能识别所有类型的变量,甚至是复杂的类型:列表,字典,对象等。
使用范例:
<p>A value from a dictionary: {{ mydict['key']}}</p><p>A value from a list: {{ mylist[3] }}</p><p>A value from a list,with a variable index: {{ mylist[myintvar] }}</p><p>A value from a object's method: {{ myobj.somemethod() }}</p>
过滤器
使用过滤器修改变量,过滤器名在变量名后,中间用竖线分隔:
Hello, {{ name|capitalize }}
这样将会以首字母大写形式显示name的值。
常用的过滤器:
- safe : 渲染时不转义
- capitalize : 值的首字母转换为大写,其他字母小写
- lower : 值转换为小写形式
- upper : 值转换为大写形式
- title : 值中的每个单词的首字母转换为大写
- trim : 值的首尾空格去掉
- striptags : 渲染之前把值中所有的HTML标签删掉
特别注意safe
这个的使用场景,默认情况下,Jinja2会转义所有的变量。
我们有时需要不转义的HTML代码,此时需要safe过滤器。
不要在不可信的值上使用safe过滤器。
完整过滤器列表.
控制结构
渲染流程需要引入控制结构。
条件控制:
{% if user %} Hello, {{ user }}!{% else %} Hello, stranger!{% endif %}
渲染一组元素:
<ul> {% for comment in comments %} <li>{{ comment }}</li> {% endfor %}</ul>
宏:
{% macro render_comment(comment) %} <li> {{ comment }} </li>{% endmacro %}<!--利用宏--><ul> {% for comment in comments %} {{ render_comment(comment)}} {% endfor %}</ul>
可以将宏单独保存,需要使用的模板中引入即可。
<% import 'macros.html' as macros %><ul> <% for comment in comments %> {{ macros.render_comment(comment) }} <% endfor %></ul>
多处重复使用时,可以用包含来做。
<% include 'common.html' %>
模板继承
<!DOCTYPE html><html><head> <% block head %> <title>{% block title %} {% endblock %}</title> <% endblock %></head><body> <% block body %> <% endblock %></body></html>
其中block标签定义的元素可以在衍生模板中修改。
扩展语法:
<% extends "base.html" %><% block title %>Index<% endblock %><% block head %> {{ super() }} <style> </style><% endblock %><% block body %><h1>Hello World! </h1><% endblock %>
通过extends
可以达到重复利用模板。
使用Flask-Bootstrap集成Twitter Bootstrap
Bootstrap是客户端框架,主要提供CSS,JS文件,在JS代码宏实例化所需要的组件,这些操作的理想场所是模板。
程序中集成Bootstrap,需要对模板做必要的改动。
更简单的做法是:使用Flask-Bootstrap扩展。
$ pip install flask-bootstrap
修正: 新版的Flask导入包是:
from flask_script import Managerfrom flask_bootstrap import Bootstrap
而以前的flask.ext.xx
被弃用了,新版的命名空间是flask_xx
使用步骤
基于模板继承机制,使用一个包含所有Bootstrap文件的基模板。
{% extends "bootstrap/base.html" %}
Jinja2的extends指令从Flask-Bootstrap中导入bootstrap/base.html
,实现了模板继承。
而base.html
提供了一个网页框架,引入了Bootstrap中的所有CSS和JS文件。
此外,基模板中定义了可在衍生模板中重新定义的块。
bootstrap/base.html中的块
- doc : 整个HTML文档
- html_attribs :
<html>
标签的属性 - html :
<html>
标签中的内容 - head :
<head>
标签中的内容 - title :
<title>
标签中的内容 - metas : 一组
<meta>
标签 - styles : CSS定义
- body_attribs :
<body>
标签的属性 - body :
<body>
标签中的内容 - navbar : 用户定义的导航条
- content : 用户定义的页面内容
- scripts : 文档底部的JS声明
直接重定义块会导致问题,因此,如果程序需要向已有内容的块中添加新内容,必须使用super()
函数。
示例:添加新的jS文件
{% block scripts %}{{ super() }}<script type="text/javascript" src="my-script.js"></script>{% endblock %}
补充:bootstrap/base.html概览:
{% block doc -%}<!DOCTYPE html><html{% block html_attribs %}{% endblock html_attribs %}>{%- block html %} <head> {%- block head %} <title>{% block title %}{% endblock title %}</title> {%- block metas %} <meta name="viewport" content="width=device-width, initial-scale=1.0"> {%- endblock metas %} {%- block styles %} <!-- Bootstrap --> <link href="{{bootstrap_find_resource('css/bootstrap.css', cdn='bootstrap')}}" rel="stylesheet"> {%- endblock styles %} {%- endblock head %} </head> <body{% block body_attribs %}{% endblock body_attribs %}> {% block body -%} {% block navbar %} {%- endblock navbar %} {% block content -%} {%- endblock content %} {% block scripts %} <script src="{{bootstrap_find_resource('jquery.js', cdn='jquery')}}"></script> <script src="{{bootstrap_find_resource('js/bootstrap.js', cdn='bootstrap')}}"></script> {%- endblock scripts %} {%- endblock body %} </body>{%- endblock html %}</html>{% endblock doc -%}
自定义错误页面
场景:在浏览器地址栏输入了不可用的路由,则会有一个状态码为404的错误页面。为了风格一致,需要自定义一个界面。
两个错误代码返回值:
+ 404 : 客户端请求未知页面或路由
+ 500 :有未处理的异常
#异常处理@app.errorhandler(404)def page_not_found(e): return render_template('404.html'),404@app.errorhandler(500)def internal_server_error(e): return render_template('500.html'),500
可见,也是返回渲染出来的页面,而这些待渲染的页面模板就是我们需要编写的。
问题在于:手工编写会带来许多重复劳动,如何解决这个问题?
模板继承机制。
我们在templates/base.html
中写成下面这个样子:
{% extends "bootstrap/base.html" %}{% block title %}Flasky{% endblock %}{% block navbar %}<div class="navbar navbar-inverse" role="navigation"> <div class="container"> <div class="navbar-header"> <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="navbar-brand" href="/">Flasky</a> </div> <div class="navbar-collapse collapse"> <ul class="nav navbar-nav"> <li><a href="/">Home</a></li> </ul> </div> </div></div>{% endblock %}{% block content %} <div class="container"> {% block page_content %}{% endblock %} </div>{% endblock %}
异常渲染界面基于这个基模板来写,而不是基于bootstrap的基模板来做。
于是,404.html写作如下:
{% extends "base.html" %}{% block title %} Flasky -- Page Not Found {% endblock %}{% block page_content %}<div class="page-header"> <h1> Not Found</h1></div>{% endblock %}
链接
任何具有多个路由的程序需要可以连接不同页面的链接。
模板中直接编写简单路由的URL链接不难,但是对于包含可变部分的动态路由,在模板中构建正确的URL就困难。此外,直接编写URL会对代码中定义的路由产生不必要的依赖关系。重新定义路由,模板中的连接就会失效。
这个更通俗的解释是:在html中写链接是很容易做到的,但是,这是一种硬编码的做法,更好的做法是通过辅助函数来构造,能够解构出层次来,模块化编写程序。
url_for()
辅助函数,使用程序URL映射中保存的信息生成URL。
url_for()函数的用法
最简单的用法是:url_for()
以视图函数名或者app.add_url_route()
定义路由时使用的端点名作为参数,返回的是对应的URL。
e.g.
url_for('index')
返回的是'/'
.
url_for('index',_external=True)
返回的是绝对地址,即地址栏中的全部地址字符串。
两种运用场景:
- 程序内部使用相对地址即可
- 程序外部使用绝对地址
注意拿到相对地址是相对于根目录的。
url_for()使用动态参数
将动态部分作为关键字参数传入,返回的是值替换以后的字符串。
url_for()传递额外的参数
此函数的参数关键字不仅限于动态路由中的参数,还能将任何额外参数添加到查询字符串中。这是个很有用的特性。
url_for('index',page=2)
返回结果就是/?page=2
.
静态文件
Web程序不仅仅由Python代码和模板组成,大多数场景下会用到静态文件。
如:
- 图片
- JS源代码
- CSS
URL映射中有一个static路由,对静态文件的引用当做一个特殊的路由。
/static/<filename>
利用:
url_for('static', filename='css/style.css',_external=True)
得到的结果是:http://localhost:5000/static/css/styles.css
默认设置下,Flask在程序根目录中名为static的子目录中寻找静态文件。
Flask-Moment本地化日期和时间
服务器可以使用UTC时间来统一显示,但是UTC显示时间的格式不够友好,会让人感到困惑,更好的方式是采用当地惯用时间格式。
解决方案是:把时间单位发送给Web浏览器转换为当地时间,服务器上只用UTC时间。
moment.js是一个很棒的库,在Flask中可以用Flask-Moment来集成到Jinja2中。
安装
pip install flask-moment
使用语法
from flask_moment import Momentmoment = Moment(app)
除了moment.js库,Flask-Moment 还依赖jquery库。
因此需要在HTML文档的某个地方引入这两个库,可直接引入:
<script src="{{bootstrap_find_resource('js/bootstrap.js', cdn='bootstrap')}}"></script>
。
也可使用扩展提供的辅助函数:
{% block scripts %}{{ super() }}{{ moment.include_moment() }} {% endblock %}
在Bootstrap框架下,已经引入了JQuery,所以只需要再引入moment.js即可。
Flask-Moment向模板开放了moment类,所以在模板中可以调用moment的方法进行渲染。
<!--templates/index.html--><p>The local date and time is {{ moment(current_time).format('LLL') }}.</p><p>That was {{ moment(current_time).fromNow(refresh=True) }}</p>
在hello.py中:
from datetime import datetime@app.route('/')def index(): return render_template('index.html',current_time=datetime.utcnow())
但是实际测试未通过。
函数的使用:
- format()
- fromNow()
- fromTime()
- calender()
- valueOf()
- unix()
具体可查阅文档来学习moment.js的格式化选项。
- Flask中的Jinja2模板使用
- Flask Jinja2模板
- Flask的jinja2模板中自定义过滤器的使用
- Flask web 开发 Jinja2 模板
- Flask-Jinja2模板学习总结
- Flask模板引擎——Jinja2
- Python学习:Flask框架和jinja2模板
- Flask入门(二)Jinja2 模板
- Flask(Jinja2) 服务端模板注入漏洞
- 用flask开发个人博客(9)—— Jinja2模板中的变量
- 用flask开发个人博客(10)—— Jinja2模板中的控制结构
- 使用Python写HTML 文件使用jinja2中的模板
- flask jinja2
- flask--jinja2
- Flask笔记(2)--flask的jinja2模板引擎
- flask中jinja2设置使用全局变量
- Python Flask Web 第四课 —— 模板引擎Jinja2
- Flask学习总结笔记(3)-- Jinja2模板引擎之一
- Oracle学习笔记(二)
- win7和VMware中Ubuntu的通过nat上网
- Oracle学习笔记(三)
- 欢迎使用CSDN-markdown编辑器
- Linux---Linux下文本文件合并和去除重复操作
- Flask中的Jinja2模板使用
- 单例设计模式
- 万达电商折戟之谜
- Oracle学习笔记(四)
- 你大概走了假敏捷:认真说说敏捷的实现和问题(手绘版)
- jQuery
- mongodb查看数据库和表的信息
- 08_代码结构
- NYOJ 188 Arbitrage map 建图 汇率转换