Flask学习之模板
Flask模板
变量
我们之前学过动态路由,如下所示:
@app.route('/user/<name>')
def user(name):
return '<h1>Hello, %s!</h1>' % name
我们在请求url时候可以后面带一个名字,然后页面会显示hello, xxx!
,一个很简单的回应,但是现在我需要返回一个html文件,并且要也是返回给客户端显示hello,xxx!
,怎么办?
这时候就要用到Flask的模板功能了。
怎么做呢?看下面代码:
hello.html中:
<h1>Hello, {{ name }}!</h1>
app.py中
from flask import Flask, render_template
app = Flask(__name__, template_folder='templates')
@app.route('/user/<name>')
def user(name):
return render_template('hello.html', name=name)
这样我们即可在hello.html
中增加一个变量进去。
这就是Flask中模板起的作用,模板是一个包含响应文本的文件,其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染。
为了渲染模板,Flask 使用了一个名为Jinja2
的强大模板引擎。
上例中的 name=name 是关键字参数左边的“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 an object's method: {{ myobj.somemethod() }}.</p>
过滤器
Jinjia2还提供过滤器来修改变量,过滤器名添加在变量名之后,中间使用竖线分隔。如:
Hello, {{ name|capitalize }}
模板以首字母大写形式显示变量 name 的值。常用过滤器:
safe 渲染值时不转义
capitalize 把值的首字母转换成大写,其他字母转换成小写
lower 把值转换成小写形式
upper 把值转换成大写形式
title 把值中每个单词的首字母都转换成大写
trim 把值的首尾空格去掉
striptags 渲染之前把值中所有的 HTML 标签都删掉
safe要说明一下,如果一个变量的值为 <h1>Hello</h1>
,Jinja2 会将其渲染成 <h1>Hello</h1>,
浏览器能显示这个 h1 元素,但不会进行解释。这怎么理解呢,我们来看实例就好:
hello.html中:
<h1>hello {{name}}</h1>
app.py中
from flask import Flask, render_template
app = Flask(__name__, template_folder='templates')
@app.route('/home/<name>')
def home(name):
name = '<h1>test</h1>' # 这里对name进行重新赋值了,如果不赋值就是url中的name值
return render_template('hello.html', name=name)
if __name__ == '__main__':
app.run(debug=True)
这时候你输入http://localhost:5000/home/1
,页面会显示:
hello
<h1>test</h1>
!
你查看页面源代码发现是这样的:
<h1>hello <h1>test</h1>!</h1>
然后我们在hello.html中加入safe过滤器:
<h1>hello {{name|safe}}</h1>
再刷新页面可以看到页面显示正常了:
hello
test
!
两个<h1>
的标题嘛,查看源代码也是正常的:
<h1>hello <h1>test</h1>!</h1>
完整的过滤器列表可在 Jinja2 文档(http://jinja.pocoo.org/docs/templates/#builtin-filters)中查看。
控制结构
控制结构就是所谓的if else , for , 宏定义,模板继承
{ % if user % }
Hello, {{ user }}!
{ % else % }
Hello, Stranger!
{ % endif % }
for循环
<ul>
{ % for comment in comments % }
<li>{{ comment }}</li>
{ % endfor % }
</ul>
宏定义就是和定义函数差不多,使用macro定义函数:
{ % macro func_name(comment) % }
<li>{{ comment }}</li>
{ % endmacro % }
<ul>
{ % for comment in comments % }
{{ func_name(comment) }}
{ % endfor % }
</ul>
我们也可以定义宏到另外的html文件中,然后引入即可:
{ % import 'macros.html' as macros % }
<ul>
{ % for comment in comments % }
{{ macros.render_comment(comment) }}
{ % endfor % }
</ul>
模板继承
首先我们创建一个基础模板:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
{% block head %}{% endblock %}
</head>
<body>
<h1>this is father text</h1>
{% block body %}{% endblock %}
</body>
</html>
模板通过extends来继承,使用 {% block %}
标签定义了四个子模板可以重载的块,{% block title %}
这里 title是指块的名字,子模板通过声明这个title模块就可以更改这个模块的内容。 block 标签所做的的所有事情就是告诉模板引擎: 一个子模板可能会重写父模板的这个部分。
然后我们创建一个子模板:
{% extends 'base.html' %}
{% block title %}
名字
{% endblock %}
{% block head %}
<style>
</style>
<link rel="stylesheet" href="">
<script>
</script>
{% endblock %}
{% block body %}
<h1>this is child content</h1>
{% endblock %}
修改app.py,增加接口
@app.route('/home/test')
def test():
return render_template('index.html')
浏览器打开页面,我们可以看到页面显示:
this is father text
this is child content
查看源代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
名字
</title>
<style>
</style>
<link rel="stylesheet" href="">
<script>
</script>
</head>
<body>
<h1>this is father text</h1>
<h1>this is child content</h1>
</body>
</html>
Flask-bootstrap的使用
bootstrap是Twitter开发的一个开源框架,它可以简单快速的创建简洁有吸引力的页面。详细了解请自行搜索了解。
这里我们使用Flask-bootstrap这个Flask扩展,使用pip安装即可:
(venv) $ pip install flask-bootstrap
然后我们在程序创建后初始化一下这个扩展:
from flask import Flask, render_template
from flask_bootstrap import Bootstrap
app = Flask(__name__, template_folder='templates')
# 这里初始化bootstrap,并传入程序实例
bootstrap = Bootstrap(app)
再新建一个user.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">
<div class="page-header">
<h1>Hello, {{ name }}!</h1>
</div>
</div>
{% endblock %}
在app.py中返回这个页面:
@app.route('/home/<name>')
def home(name):
return render_template('user.html', name=name)
打开浏览器访问,我们即可看到如下页面:
静态文件
Flask默认的静态文件存放目录是程序根目录中名为static的目录,我们可以把*.css,js,图片等静态资源放到这个目录下即可,结构如下:
├── app.py
├── LICENSE
├── requirement.txt
├── static
├── templates
└── venv
上图的static目录即是静态资源目录,venv是python虚拟环境,templates是模板文件目录。requirement.txt是python库的要求文件。