chapter3 - 使用模板
3.1 Jinja2模板引擎
个人觉得模板主要用于前端的显示部分。模板中用到python语句的地方,需要用{% %}包围起来,并且有开始和结束两行,而变量名则需要用两个大括号包围:{{ }}。如下面为一个条件控制语句:
{% if user %}
Hello, {{ user }}!
{% else %}
Hello, Stranger!
{% endif %}
模板中需要注释掉部分语句时,也需要用一对大括号内加一对#号包围,如:
{# for message in messages #}
上面代码中的for循环将被注释掉而不会被执行
3.1.1 渲染模板
Jinja2是Flask默认使用的模板引擎。默认情况下,Flask程序在程序文件夹中的templates子文件夹中寻找模板。简单的模板使用示例:
from flask import Flask from flask import render_template app = Flask(__name__) @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__': app.run()
如上,render_template函数的第一个参数是模板的文件名,后面的参数都是键值对,表示模板文件中接收的变量。如上的user()函数中,将会把name传给user.html文件。
最简单的user.html文件(位置为templates/user.html)可以是:
<h1>Hello, {{ name }}!</h1>
由此,通过user()函数传入的name参数将会在模板中的相应位置显示
3.1.2 变量
Jinja2可以识别所有类型的变量,包括列表、字典、对象。也可以使用过滤器修改变量,变量名和过滤器之间使用竖线分隔。如下述模板以首字母大写形式显示变量name的值:
Hello, {{ name|capitalize }}
以下是Jinja2提供的部分常用的过滤器:
过滤器名 说明 safe 渲染值时不转义 capitalize 把值的首字母转换成大写,其它字母转换成小写 lower 把值转换成小写形式 upper 把值转换成大写形式 title 把值中每个单词的首字母都转换成大写 trim 把值的首尾空格去掉 striptags 渲染之前把值中所有的HTML标签都删掉
值得注意的是safe过滤器。默认情况下,Jinja2会转义所有变量。如果把 '<h1>Hello</h1>'转换成'<h1>Hello</h1>',如果需要显示变量中存储的HTML代码,就可以使用safe过滤器,但千万不要在不可信的值上使用safe过滤器。 完整的过滤器列表在:Template Designer Documentation
3.1.3 控制结构
Jinja2的控制结构与一般编程语言的控制语句有点类似。
- 条件控制语句
{% 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>
还可以将其写入单独的文件中,以避免重复:
{% include 'common.html' %}
- 模板继承
模板继承类似于Python中的类继承。先写一个名为base.html的基模板:
<html> <head> {% block head %} <title>{% block title %}{% endblock %} - My Application</title> {% endblock %} <body> {% block body %} {% endblock %} </body> </head> </html>
如上,在block标签中的元素是可以在衍生模板中修改的,如:
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style>
</style>
{% endblock %}
{% block body %}
<h1>Hello, World!</h1>
{% endblock %}
extends指令声明这个模板衍生自base.html。其后基模板中的3个块title、head、body被重新定义。
注意在新定义的head块中,因为在基模板中其内容不是空的,所以要使用super()来获取原来的内容
模板中的所有block都必须要有结束的block语句
3.2 使用Flask-Bootstrap集成Twitter Bootstrap
Bootstrap是一个前端的js框架,可以用创建优雅的UI。可以使用pip安装:(venv) $ pip install flask-bootstrap
初始化Flask-Bootstrap
在代码中加入:
# 原书中的代码是 from flask.ext.bootstrap import Bootstrap # 但是我在python3.5中运行时,被提示说这种用法已经过时了 # 而应该使用下面这种导入方法 from flask_bootstrap import Bootstrap #... # 下面这行代码应在app = Flask(__name__)之后 bootstrap = Bootstrap(app) #...
- 在模板中使用Flask-Bootstrap
修改templates/base.html文件:
{% extends "bootstrap/base.html" %}
{% block title %}Flasky{% endblock %}
{% block navbar %}
<div class="navbar navbar-invrese" 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">
<div class="page-header">
<h1>Hello, {{ name }}!</h1>
</div>
</div>
{% endblock %}
3.3 自定义错误页面
在没有定义错误页面之前,如果访问一个不存在的URL,浏览器会显示一个它内置的404页面。
Flask提供了errorhandler()修饰器,允许程序自定义错误页面。如下两段代码可以指定特定的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
为了方便使用,作者在此处把前面定义好的user.html模板改写作为项目里面的基模板base.html,然后再新建user.html模板继承自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 %}
基模板主要定义了默认标题和导航栏内容,内容部分content block只放了一个div,其中包含了一个名为page_content的空白块,块中的内容由衍生模板定义,作为页面主体内容显示。
由此重新组织的templates/user.html页面为:
{% extends "base.html" %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Hello, {{ name }}!</h1>
</div>
{% endblock %}
404错误页面templates/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 %}
浙公网安备 33010602011771号