03.flask模板
配套视频教程
模板概述
一. 为什么要使用模板
视图函数有两个作用, 一个是业务逻辑一个是表现逻辑, 举例说明:
用户在网站注册了一个新账号, 用户在表单中输入电子邮件地址和密码, 点击提交按钮, 服务器接收到包含用户输入的请求, 然后Flask把请求分发到处理注册请求的视图函数。 这个视图函数需要访问数据库, 添加新用户(业务逻辑), 然后生成相应回送浏览器(表现逻辑)。
两个完全独立的作用被混淆到一起会使代码难以理解和维护, 所以我们选择把表现逻辑(响应)迁移到模板当中去。
模板是包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。为了渲染模板,Flask 使用一个名为 Jinja2 的强大模板引擎。
二. 如何使用模板
- 如何渲染模板:
- 模板放在
templates
文件夹下 - 从
flask
中导入render_template
函数。 - 在视图函数中,使用
render_template
函数,渲染模板。注意:只需要填写模板的名字,不需要填写templates
这个文件夹的路径。
- 模板放在
- 模板传参:
- 如果只有一个或者少量参数,直接在
render_template
函数中添加关键字参数就可以了。 - 如果有多个参数的时候,那么可以先把所有的参数放在字典中,然后在
render_template
中,
使用两个星号,把字典转换成关键参数传递进去,这样的代码更方便管理和使用。
- 如果只有一个或者少量参数,直接在
- 在模板中,如果要使用一个变量,语法是:
{{params}}
- 访问模型中的对象属性或者是字典,可以通过
{{params.property}}
的形式,或者是使用{{params['age']}}
.
示例代码
template01 .py
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
# 类
class Person(object):
name = u'p17bdw'
age = 18
p = Person()
context = {
'username': u'c17bdw',
'gender': u'男',
'age': 17,
'person': p, # 声明
'websites': {
'baidu': 'www.baidu.com',
'google': 'www.google.com'
}
}
return render_template('anthoer/index.html',**context)
if __name__ == '__main__':
app.run(debug=True)
anthoer/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
这是HTML文件中出现的文字
<p>用户名:{{ username }}</p>
<p>性别:{{ gender }}</p>
<p>年龄:{{ age }}</p>
<hr>
<p>名字:{{ person['name'] }}</p>
<p>年龄:{{ person.age }}</p>
<hr>
<p>百度:{{ websites['baidu'] }}</p>
<p>谷歌:{{ websites['google'] }}</p>
</body>
</html>
if判断
-
语法:
{% if xxx %} {% else %} {% endif %}
-
if的使用,可以和python中相差无几。
示例代码
if_statement .py
# 输入 http://127.0.0.1:5000/1/ 为登录状态,否则为未登录状态。
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/<is_login>/')
def index(is_login):
if is_login == '1':
user = {
'username': u'17bdw',
'age':20
}
return render_template('index.html',user=user)
else:
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
{% if user and user.age > 18 %}
<a href="#">{{ user.username }}</a>
<a href="#">注销</a>
{% else %}
<a href="#">登录</a>
<a href="#">注册</a>
{% endif %}
</body>
</html>
for循环遍历列表和字典
1. 字典的遍历,语法和`python`一样,可以使用`items()`、`keys()`、`values()`、`iteritems()`、`iterkeys()`、`itervalues()`
`{% for k,v in user.items() %} <p>{{ k }}:{{ v }}</p> {% endfor %}`
2. 列表的遍历:语法和`python`一样。
`{% for website in websites %} <p>{{ website }}</p> {% endfor %}`
示例代码
for_statement .py
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
# for遍历字典
@app.route('/')
def index():
books = [
{
'name': u'西游记',
'author': u'吴承恩',
'price': 109
},
{
'name': u'红楼梦',
'author': u'曹雪芹',
'price': 200
},
{
'name': u'三国演义',
'author': u'罗贯中',
'price': 120
},
{
'name': u'水浒传',
'author': u'施耐庵',
'price': 130
}
]
return render_template('index.html',books=books)
if __name__ == '__main__':
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
<thead>
<th>书名</th>
<th>作者</th>
<th>价格</th>
</thead>
<tbody>
{% for book in books %}
<tr>
<td>{{ book.name }}</td>
<td>{{ book.author }}</td>
<td>{{ book.price }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
过滤器
-
介绍和语法:
- 介绍:过滤器可以处理变量,把原始的变量经过处理后再展示出来。作用的对象是变量。
- 语法:
{{ avatar|default('xxx') }}
-
default过滤器:如果当前变量不存在,这时候可以指定默认值。
-
length过滤器:求列表或者字符串或者字典或者元组的长度。
-
常用的过滤器:
abs(value):返回一个数值的绝对值。示例:-1|abs
default(value,default_value,boolean=false):如果当前变量没有值,则会使用参数中的值来代替。示例:name|default('xiaotuo')——如果name不存在,则会使用xiaotuo来替代。boolean=False默认是在只有这个变量为undefined的时候才会使用default中的值,如果想使用python的形式判断是否为false,则可以传递boolean=true。也可以使用or来替换。
escape(value)或e:转义字符,会将<、>等符号转义成HTML中的符号。示例:content|escape或content|e。
first(value):返回一个序列的第一个元素。示例:names|first
last(value):返回一个序列的最后一个元素。示例:names|last。length(value):返回一个序列或者字典的长度。示例:names|length。
join(value,d=u''):将一个序列用d这个参数的值拼接成字符串。
safe(value):如果开启了全局转义,那么safe过滤器会将变量关掉转义。示例:content_html|safe。
int(value):将值转换为int类型。
float(value):将值转换为float类型。
lower(value):将字符串转换为小写。
upper(value):将字符串转换为小写。
replace(value,old,new): 替换将old替换为new的字符串。
truncate(value,length=255,killwords=False):截取length长度的字符串。
striptags(value):删除字符串中所有的HTML标签,如果出现多个空格,将替换成一个空格。
trim:截取字符串前面和后面的空白字符。
string(value):将变量转换成字符串。
wordcount(s):计算一个长字符串中单词的个数。
示例代码
filter_demo .py
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
comments = [
{
'user': u'admin',
'content': 'xxxx'
},
{
'user': u'tesr',
'content': 'xxxx'
}
]
return render_template('index.html',comments=comments)
if __name__ == '__main__':
app.run(debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>过滤器</title>
</head>
<body>
# 如果avatar这个变量不存在,就使用default过滤器提供的值
<img src="{{ avatar|default('http://avatar.csdn.net/1/D/B/3_hmzkekek41.jpg') }}" alt="">
<hr>
# length 计算长度
<p>评论数:({{ comments|length }})</p>
<ul>
{% for comment in comments %}
<li>
<a href="#">{{ comment.user }}</a>
<p>{{ comment.content }}</p>
</li>
{% endfor %}
</ul>
</body>
</html>
继承和block
-
继承作用和语法:
- 作用:可以把一些公共的代码放在父模板中,避免每个模板写同样的代码。
- 语法:
{% extends 'base.html' %}
-
block实现:
- 作用:可以让子模板实现一些自己的需求。父模板需要提前定义好。
- 注意点:字模板中的代码,必须放在block块中。
示例代码
app.py
#encoding: utf-8
from flask import Flask,render_template
app = Flask(__name__)
@app.route('/')
def index():
return render_template('index.html')
@app.route('/login/')
def login():
return render_template('login.html')
if __name__ == '__main__':
app.run(debug=True)
index.html
{% extends 'base.html' %}
{% block head %}
<style>
</style>
<link rel="stylesheet" href="">
<script></script>
{% endblock %}
{% block title %}
首页
{% endblock %}
{% block main %}
<h1>这是首页</h1>
{% endblock %}
base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<style>
.nav{
background: #3a3a3a;
height: 65px;
}
ul{
overflow: hidden;
}
ul li{
float: left;
list-style: none;
padding: 0 10px;
line-height: 65px;
}
ul li a{
color: #fff;
}
</style>
{% block head %}{% endblock %}
</head>
<body>
<div class="nav">
<ul>
<li><a href="/">首页</a></li>
<li><a href="/login">发布问答</a></li>
</ul>
</div>
{% block main %}{% endblock %}
</body>
</html>
login.html
{% extends 'base.html' %}
{% block title %}
登录
{% endblock %}
{% block main %}
<h1>这是登录页面</h1>
{% endblock %}
使用Flask-Bootstrap集成Bootstrap
Bootstrap 是 Twitter 开发的一个开源 Web 框架,它提供的用户界面组件可用于创建整洁且具有吸引力的网页,而且兼容所有现代的桌面和移动平台 Web 浏览器。
要想在应用中集成 Bootstrap,最直接的方法是根据 Bootstrap 文档中的说明对 HTML 模板进行必要的改动。不过,这个任务使用 Flask 扩展处理要简单得多,而且相关的改动不会导致主逻辑凌乱不堪。
我们要使用的扩展是 Flask-Bootstrap,它可以使用 pip 安装:
(venv) $ pip install flask-bootstrap
Flask 扩展在创建应用实例时初始化。
初始化 Flask-Bootstrap。
from flask_bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
扩展通常从 flask_<name>
包中导入,其中 <name>
是扩展的名称。多数 Flask 扩展采用两种初始化方式中的一种。在示例中,初始化扩展的方式是把应用实例作为参数传给构造函数。
初始化 Flask-Bootstrap 之后,就可以在应用中使用一个包含所有 Bootstrap 文件和一般结构的基模板。应用利用 Jinja2 的模板继承机制来扩展这个基模板。
templates/user.html:使用 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="/">Home</a></li>
</ul>
</div>
</div>
</div>
{% endblock %}
{% block content %}
<div class="container">
<div class="page-header">
<h1>Hello, {{ name }}!</h1>
</div>
</div>
{% endblock %}
Jinja2 中的 extends
指令从 Flask-Bootstrap 中导入 bootstrap/base.html,从而实现模板继承。Flask-Bootstrap 的基模板提供了一个网页骨架,引入了 Bootstrap 的所有 CSS 和 JavaScript 文件。
上面这个 user.html 模板定义了 3 个区块,分别名为 title
、navbar
和 content
。这些区块都是基模板提供的,可在衍生模板中重新定义。title
区块的作用很明显,其中的内容会出现在渲染后的 HTML 文档头部,放在 <title>
标签中。navbar
和 content
这两个区块分别表示页面中的导航栏和主体内容。
在这个模板中,navbar
区块使用 Bootstrap 组件定义了一个简单的导航栏。content
区块中有个 <div>
容器,其中包含一个页头。之前版本中的欢迎消息,现在就放在这个页头里。改动之后的应用如图所示。
url链接
使用url_for(视图函数名称)
可以反转成url。
在模板中直接编写简单路由的 URL 链接不难,但对于包含可变部分的动态路由,在模板中构建正确的 URL 就很困难了。而且,直接编写 URL 会对代码中定义的路由产生不必要的依赖关系。如果重新定义路由,模板中的链接可能会失效。
为了避免这些问题,Flask 提供了 url_for() 辅助函数,它使用应用的 URL 映射中保存的信息生成 URL。
url_for() 函数最简单的用法是以视图函数名作为参数,返回对应的 URL。例如,在当前版本的 app.py 应用中调用 url_for('index') 得到的结果是 /,即应用的根 URL。调用 url_for('index', _external=True) 返回的则是绝对地址,在这个示例中是 http://localhost:5000/。
使用 url_for() 生成动态 URL 时,将动态部分作为关键字参数传入。例如,url_for('user', name='john', _external=True) 的返回结果是 http://localhost:5000/user/john。
传给 url_for() 的关键字参数不仅限于动态路由中的参数,非动态的参数也会添加到查询字符串中。例如,url_for('user', name='john', page=2, version=1) 的返回结果是 /user/ john?page=2&version=1。
加载静态文件
Web 应用不是仅由 Python 代码和模板组成。多数应用还会使用静态文件,例如模板中 HTML 代码引用的图像、JavaScript 源码文件和 CSS。
在前一章中审查 app.py 应用的 URL 映射时,其中有一个 static 路由。这是 Flask 为了支持静态文件而自动添加的,这个特殊路由的 URL 是 /static/
默认设置下,Flask 在应用根目录中名为 static 的子目录中寻找静态文件。如果需要,可在 static 文件夹中使用子文件夹存放文件。服务器收到映射到 static 路由上的 URL 后,生成的响应包含文件系统中对应文件里的内容。
- 语法:
url_for('static',filename='路径')
- 可以加载
css
文件,可以加载js
文件,还有image
文件。
第一个:加载css文件
<link rel="stylesheet" href="{{ url_for('static',filename='css/index.css') }}">
第二个:加载js文件
<script src="{{ url_for('static',filename='js/index.js') }}"></script>
第三个:加载图片文件
<img src="{{ url_for('static',filename='images/zhiliao.png') }}" alt="">