Flask系列:模板

这个系列是学习《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')

Jinja2

更多jinja2 模板的语法

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,980评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,178评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,868评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,498评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,492评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,521评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,910评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,569评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,793评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,559评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,639评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,342评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,931评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,904评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,144评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,833评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,350评论 2 342

推荐阅读更多精彩内容