这个系列是学习《Flask Web开发:基于Python的Web应用开发实战》的部分笔记
虽然可以在视图中直接编写 HTTP 页面的内容,但是这种方式很原始。将与数据库交互的业务逻辑,与生成响应的表现逻辑混在了一起。一方面不适合大型、复杂页面的编写、维护,结构不清晰,另外,由于业务逻辑通常由程序员完成,而表现逻辑由设计师完成,这样双方的工作会互相影响。
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
flask 支持 MVC 模型,由程序员在视图中完成与数据库的交互——业务逻辑(M),而显示给客户端的页面在模板中定义(V),由设计师完成。
模板
是一个包含响应文本的文件(通常是 HTML),其中包含用 占位变量 表示的动态部分, 具体值只在收到具体的请求后,通过上下文才能知道,模板中最主要的是前端技术,HTLM、CSS、JS 等。
模板引擎
实现对模板的渲染,就是根据上下文,对模板中的占位变量,用真实值替换,形成最终的响应文件。
模板文件夹
默认情况下,Flask 在程序文件夹中的 templates 子文件夹中寻找模板。
模板的调用
flask 使用 jinjia2 模板引擎,为了便于使用,已经集成到 render_template 函数中,可以直接调用。
from flask import Flask, render_template
@app.route('/')
def index():
return render_template('index.html') # 注意,是包含 .html 后缀的完整文件名
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
第一个参数是模板的名称,然后是 键/值 对,name=name
左边表示模板中的占位符,右边是当前视图中的变量。意思是,将当前视图中变量name
的值,赋值给模板中名为name
的占位符,用于渲染。
变量
- 表示
{{ name }}
占位符,告诉模板引擎,这个位置的值从渲染模板时传递的数据字典中获取
- 支持的变量类型
支持所有类型,字符串、整型、列表、字典 ......
- 修改显示样式
通过使用过滤器,可以定制 变量的值 显示的效果,比如 大小写。{{ name | 过滤器 }}
- 模板变量
在模板中设置模板变量
{% set name = 'john' %}
控制结构
主要用于改变渲染流程
- 条件控制
if...else...endif
判断条件是否符合,并执行相应的语句
- 循环:for...endfor
用于渲染一组元素
- 宏:macro...endmacro
类似函数
定义一个宏,指定宏的名称、参数,调用
{% macro x(y) %}
...
{% endmacro %}
{{ x(y) }}
如果需要在多个模板中复用,可以将宏的定义放入一个文件,‘macro.html’
{% macro x(y) %}
...
{% endmacro %}
然后导入使用
import 'macro.html' as macro
{{ macro.x(y) }}
- 继承:
如果多个页面的大部分内容相同,可以定义一个母模板,包含相同的内容,然后子模板继承内容,并根据需要进行部分修改
base.html
,母模板,其中,用{% block title %}...{% endblock %}
定义了可以由子模板替换的区域,title
是区块的名称,可以有多个区块
{% block title %}Hello{% endblock %}
在子模板中,声明继承的母模板,然后用{% block title %}...{% endblock %}
指定替换哪个区块的内容,并填入自己的内容。子模板中没有指定的区块,默认使用母模板的内容
{% extends "base.html" %}
{% block title %}john{% endblock %}
如果希望能够保留母版的内容,并添加新内容,可以使用super()
{% extends "base.html" %}
{% block title %}
{{ super() }}
john
{% endblock %}
模板里面,不能同时有两个
{% extends " " %}
语句,即使另一个被注释了也不行
- 包含:
如果多个网页中都有一段内容相同,可以将相同的内容放入一个文件中comments.html
,通过include
导入
{% include 'comments.html' %}
bootstrap
Bootstrap是 Twitter 开发的一个开源框架,它提供的用户界面组件可用于创建整洁且具有吸引力的网页,而且这些网页还能兼容所有现代 Web 浏览器。
一个名为Flask-Bootstrap
的 Flask 扩展, 可以简化在程序中集成 Bootstrap 的过程。
安装:
$ pip install flask-bootstrap
初始化
从 flask.ext 命名空间中导入,然后把 程序实例传入构造方法进行初始化。
run.py
from flask.ext.bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)
初始化 Flask-Bootstrap 之后,就可以在程序中使用一个包含所有 Bootstrap 文件的基模板。 这个模板利用 Jinja2 的模板继承机制,让程序扩展一个具有基本页面结构的基模板,其中 就有用来引入 Bootstrap 的元素。
{% extends "bootstrap/base.html" %}
{% block title %}Flasky{% endblock %}
{% block navbar %}
{% 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 文件。
virtualenv 环境中,目录为
lib/python2.7/site-packages/flask_bootstrap/templates/bootstrap/
基模板中定义了可在衍生模板中重定义的块。block 和 endblock 指令定义的块中的内容可添加到基模板中。
Bootstrap 官方文档是很好的学习资源,有很多可以直接复制粘贴的示例。
自定义错误页面
像常规路由一样,Flask 允许程序使用基于模板的自定义错误页面。最常见的错误代码有两个:404,客户端请求未知页面或路由时显示;500,有未处理的异常时显示。
自定义错误页面
@app.errorhandler(404)
def page_not_found(e):
return render_template('404.html'), 404
和视图函数一样,错误处理程序也会返回响应。它们还返回与该错误对应的数字状态码。 返回指定的数字状态码似乎没有什么用 ?
url_for 生成连接
模板中可能有去往多个不同页面的链接,例如导航条。
在模板中直接编写简单路由的 URL 链接不难,但对于包含可变部分的动态路由,在模板中构建正确的 URL 就很困难。而且,直接编写 URL 会对代码中定义的路由产生不必要的 依赖关系(hardcode)。如果修改 路由、视图 的绑定关系, 模板中的链接可能会失效。
为了避免这些问题,Flask 提供了url_for()
辅助函数,它可以使用程序URL映射
中保存的信息,根据视图名称生成 URL。
例如,对于下面的视图
@app.route('/')
def index():
return '<h1>Hello World!</h1>'
调用 url_ for('index')得到的结果是/
。调用url_for('index', _external=True)返回的则是绝对地址,是http://localhost:5000/
。
在程序内(模板、视图中)生成连接程序内不同路由的链接时,使用
相对地址
就足够了,浏览器、程序能够根据当前的 URL 补全。但如果要在浏览器以外生成链接,例如在确认邮件中的链接,则必须使用绝对地址
,否则谁也不知道前缀是什么。
使用url_for()
生成链接时,将动态部分作为关键字参数
传入。例如,
@app.route('/user/<name>')
def user(name):
return render_template('user.html', name=name)
url_for ('user', name='john', _external=True)
的返回结果是 http://localhost:5000/user/john
。
默认 _external 为 False,表示生成相对路径;为 True 时,表示生成绝对路径
函数能将任何额外参数
添加到查询字符串
中。例如,
url_for('user', name='john', page=2)
的返回结果是/user/john/?page=2
对于多层的模板结构,render_template 函数中需要添加从templates
目录下文件夹开始的路径信息,render_template('main/index.html')
,结构为templates/main/index.html
,url_for() 需要用.
隔开目录,url_for('main.index.html')
。