本系列笔记是我阅读Miguel Grinberg的《Flask Web Development》的笔记,标题与书本同步。希望通过记录技术笔记的方式促进自己对知识的理解。本篇对应书本第三章:模板。
模板是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替代变量,再返回最终得到的响应字符串,这一过程成为渲染。
Jinja2模板引擎
Flask渲染模板使用的是Jinja2模板引擎。
渲染模板
hello.py 渲染模板
from flask import Flask,render_template
#...
@app.route('/')
def index():
return render_template('index.html')
@app.route('/user/<name>')
def user(name):
return render_template('user.html',name=name)
# Flask提供的render_template函数把Jinja2模板引擎集成到了程序中。
# render_template函数的第一个参数是模板的文件名。
# 随后的参数都是键值对,表示模板中变量对应的真实值。
变量
模板中使用的{{ 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 an object's method: {{ myobj.somemethod() }}.</p>
变量过滤器
过滤器名添加在变量之后,中间使用竖线分隔。
hello, {{ name|capitalize }}
常用过滤器:
过滤器名 | 说明 |
---|---|
safe | 渲染值时不转义 |
capitalize | 把值得首字母转换成大写,其他字母转换成小写 |
lower | 把值转换成小写形式 |
upper | 把值转换成大写形式 |
title | 把值中每个单词的首字母都换成大写 |
trim | 把值的首位空格去掉 |
striptags | 渲染之前把值中所有的HTML标签都删掉 |
控制结构
条件控制结构
{% 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 'macro.html' as macros %}
<ul>
{% for comment in comments%}
{{ macros.render_comment(comment)}}
{% endfor%}
</ul>
复用代码片段
{% include 'common.html' %}
模板继承
- 建一个名为base.html的基模板
<html>
<head>
{% block head %}
<title>{% block title %}{% endblock %} - My Application</title>
{% endblock %}
</head>
<body>
{% block body %}
{% endblock %}
</body>
</html>
- 衍生模板中修改block标签定义的元素
{% extends "base.html" %} #定义基模板
{% block title%}Index{% endblock %} #修改title块内容
{% block head %} #修改head块内容
{{ super() }} #原来head中有内容,用super()获取原来的内容
<style>
</style>
{% endblock %}
{% block body %} #修改body块内容
<h1>Hello, World!</h1>
{% endblock %}
使用Flask-Bootstrap集成Twitter Bootstrap
Bootstrap是Twitter开发的一个开源框架,它提供用户界面组件可用于创建整洁且具有吸引力的网页,而且这些网页还能兼容所有现代Web浏览器。Bootstrap是客户端框架,不会直接涉及服务器。可以在模板中引用Bootstrap的CSS和JavaScript文件。
安装Flask-Bootstrap扩展
(venv)$ pip install flask-bootstrap
hello.py: 初始化Flask-Bootstrap
from falsk_bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)
使用Flask-Bootstrap的模板
{% 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="/"></a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
<div class="page-header">
<h1>Hello,{{ name }}!</h1>
</div>
</div>
{% endblock %}
# 模板利用Bootstrap中的样式进行了修改
Flask-Bootstrap基模板中定义的块
块名 | 说明 |
---|---|
doc | 整个HTML文档 |
html_attribs | <html>标签的属性 |
html | <html>标签中的内容 |
head | <head>标签中的内容 |
title | <title>标签中的内容 |
metas | 一组<meta>标签 |
styles | 层叠样式表定义 |
body_attribs | <body>标签的属性 |
body | <body>标签中的内容 |
navbar | 用户定义的导航条 |
content | 用户定义的页面内容 |
scripts | 文档底部的JavaScript声明 |
自定义错误页面
利用Jinja2的模板继承机制可以让templates/base.html继承自bootstrap/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 %}
程序现在使用的模板继承自templates/base.html不是直接继承自Flask-Bootstrap的基模板。
404错误页面:继承自templates/base.html
{% extends "base.html" %}
{% block title %}Flasky - Page Not Found{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Not Found</h1>
</div>
{% endblock %}
user页面:继承自templates/base.html
{% extends "base.html" %}
{% block title %}Flasky{% endblock %}
{% block page_content %}
<div class="page-header">
<h1>Hello, {{ name }}!</h1>
</div>
{% endblock %}
链接
Flask提供了url_for()辅助函数,它可以使用程序URL映射中保存的信息生成URL。
- url_for函数最简单的用法:以视图函数名作为参数,返回对应的URL。url_for(‘index’)得到的结果是’/’
- 使用url_for生成动态地址时,将动态部分作为关键字参数传入。
url_for(‘user’,name=’john’,_external=True) - 函数能将任何额外参数添加到查询字符串中。
静态文件
使用Flask-Moment本地化日期和时间
Flask-Moment是Flask的一个程序扩展,能够在浏览器中渲染日期和时间。
安装Flask-Moment
(venv)$ pip install flask-moment
hello.py:初始化Flask-Moment
from flask_moment import Moment
moment = Moment(app)
templates/base.html: 引入 moment.js库
{% block scripts %}
{{ super() }}
{{ moment.include_moment() }}
{% endblock %}
hello.py: 加入一个datetime变量
from date.time import datetime
@app.route('/')
def index():
return render_template('index.html',current_time=datetime.utcnow())
templates/index.html: 使用Flask-Moment渲染时间戳
<p>The local date and time is {{ moment(current_time).format('LLL') }}.</p>
<p>That was {{ moment(current_time).fromNow(refresh=True) }}.</p>
本文由 EverFighting 创作,采用 **知识共享署名 3.0 中国大陆许可协议 **进行许可。
可自由转载、引用,但需署名作者且注明文章出处。