Flask建站

《Flask Web开发》笔记——第三章 模板

2019-01-08  本文已影响7人  鹿呀鹿呀快开门

在学习这一章之前,我们先谈以下MVC架构(如下图)。MVC架构指的是业务模型(Model),用户界面(View)和控制器(Controller)。这是进行一种软件设计的典范,在web设计的时候,常常采用这种架构。
看看前面第二章的hello.py,在Flask中一般把其中的hello_world()函数称为视图(view)函数,但是实际上这种称法并不确切。但是这个程序中,hello_world()函数确实返回了响应的内容,就是 return 'hello world'。这种做法在实际web开发的时候却会遇到问题,因为真实呈现给用户的网页往往非常复杂,把后端的处理方式(书中称为业务逻辑)和前端呈现给大家的内容(书中称为表现逻辑)混在一起,导致视图函数(一定要记住,Flask中的视图函数,实际上并非MVC中的V,而是属于MVC中的C)非常臃肿,变得难以维护。
简单地说,用户看不见的部分是业务逻辑。而用户看见的部分是表现逻辑。

MVC架构

一个类比:
这里突然想到,进行web开发与组织一场大型晚会很类似,如果80个人计划筹备一场晚会,如果所有人都是幕后工作人员,来指挥如何开展各项工作,所有人也都是演员,都需要上台演出,仓库里的道具大家都可以安排使用。这样在布置舞台,排练节目,分配道具资源的时候,一定会乱成一团。
于是,大家分了一下工,成立了一个以导演为主的管理团队来进行总体负责,另外一部分人成立了演出团队,专门排练节目呈现给观众,还有一部分人负责各项资源的统一管理。这样就形成了一个MVC架构,M就是资源管理团队,管理道具仓库和制定仓库资源调配规则,V就是演员团队,负责把节目呈现给观众,C就是管理团队,根据观众的喜好和反馈安排节目。当然,这个类比并不绝对,因为晚会安排好之后,和观众的互动与web不太一样,但大体上还是很类似的。

业务逻辑与表现逻辑

那么,实际的Flask中,需要将业务逻辑和表现逻辑进行分离,而呈现给用户端的部分,采用模板来实现。
模板是一个包含响应文本的文件, 其中包含用占位变量表示的动态部分,其具体值只在请求的上下文中才能知道。 使用真实值替换变量,再返回最终得到的响应字符串,这一过程称为渲染(render)。为了渲染模板, Flask 使用了一个名为 Jinja2 的强大模板引擎。

1. Jinja2模板引擎

模板才是MVC架构中真正的View。所谓模板,就是专门负责浏览器能够理解的HTML部分。
那么,你可能会问,我们做好一个模板放在那里调用就可以了,这个Jinga2,这个“神社[じんじゃ]”,这个模板引擎到底是干什么的呢?


模板到最终HTML流程

从上图中看到,模板引擎就模板文件和数据结合在一起,生成了最终的HTML文档。由此我们可以总结如下:

我想说:模板引擎不生产模板,只是模板的加工匠。
我还想说:模板引擎是模板文件及数据与HTML文档实现之间的一座桥梁。

而在Flask中集成的模板引擎就是jinja2模板引擎,而满足jinja2模板引擎要求的模板就是jinja2模板。

2. 模板的渲染方法

不知道为什么,说到渲染(render)这个词语,总感觉特别高大上。但其实通俗一点的比喻:模板就是一个毛坯房,房型格局都定下来了。渲染就是装修,你可以根据需求进行装修,放置家具,最终可以入住。
那这个装修工就是Flask的视图函数。Flask提供的render_template函数把Jinja2模板引擎集成到程序中。以如下的代码来示例模板的渲染:

from flask import Flask, render_template

app = Flask(__name__)

@app.route('\')
def index():
    return render_template('index.html')

@app.route('\use\<name>')
def user(name):
return render_template('user.html', name=name)

而在这里,视图函数index()中,通过render_template函数引入了模板index.html, 而视图函数user(name)通过render_template函数引入了模板user.html, 并将值赋给了模板中的变量name。这里,render_templates函数的第一个参数是模板的文件名,后面的参数都应该是键值对,表示模板中变量对应的真实值。
此处,这两个模板分别为如下:

<h1>Hello World!</h1>
<h1>Hello, {{ name }}!</h1>

这里我们就来看看模板是如何渲染的。很明显,视图函数index()直接返回了index.html文件,并没有对模板作任何改动。
而视图函数user(name)对模板给出了一个数字,就是参数name,这个参数可以赋值给模板user.html中的某个变量。我们接着从render_template函数的第二个参数name=name可以知道,user.html中存在一个变量名name,视图函数的输入值被赋给了这个变量。我们看看user.html中的这个变量吧。它的形式是{{ name }},在Jinja2模板中,这种{{ 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>

也可以使用过滤器修改变量,如下为使用过滤器的示例:

<p>Hello, {{ name|capitalize }}</p>

Jinja2提供部分常用的过滤器如下表所列。


Jinja2变量过滤器

除了上面所用到的直接对模板占位符处进行赋值,Jinja2还提供了多种控制流程,用来改变模板的渲染过程。这些控制结构包括:

{% 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>

这里解释一下:在上面代码的前三行中,定义了一个宏。这个宏可以看作是python的函数render_comment(comment),其作用是在模板中插入comment的值。后面五行中,完成了对这个宏的调用。
另外一点是,macro可能会反复使用到,可以将其保存在单独的文件中,然后在需要的时候导入到模板中。假如macro被保存在macros.html这个文件中,而在导入的时候,需要用到的语句是{% import 'macros.html' as macros %}

现在对Jinja2模板引擎的控制结构作一下小结如下图:


Jinja2控制结构

3. 使用Flask-Bootstrap集成Twitter Bootstrap

Bootstrap是Twitter开发的一个开源框架。如下图LOGO下面的描述:简洁、直观、强悍的前端开发框架,让web开发更迅速、简单。因此,这是一个前端开发框架,不会涉及到服务器。

Bootstrap
而这样一个开源框架,提供了前端所用到的一些层叠样式(CSS)和JavaScript文件。而Flask-Bootstrap这个Flask扩展,可以简化我们将Bootstrap集成到程序这个过程。
一个注意的地方,前面也提到过,在示例3-4中,提到的这种导入Flask-Bootstrap扩展的方式是错误的,在python3中,不采用from flask.ext.bootstrap import Bootstrap这个语句来导入,而是采用如下方式:
from flask_bootstrap import Bootstrap
# ...
bootstrap = Bootstrap(app)

Flask-Bootstrap的使用方式参考书中的方式应该很好理解,这里就不在赘述。

4. 定义错误页面

常见的错误代码有如下这两个,可以分别自定义错误页面,在对应错误发生时显示该页面。

5. 链接

url_for()函数可以使用程序URL映射中保存的信息生成URL。其最简单的用法是使用视图函数名为参数,返回对应的URL。
例如:url_for('index'),会返回视图函数index()所对应的URL。
url_for()函数在生成动态地址时,动态部分可以作为关键字参数传入。例如url_for ('user', name='john', _external=True)这种形式。
传入url_for()的关键字参数不仅限于动态路由中的参数。函数能将任何额外参数添加到查询字符串中。例如,url_for('index', page=2) 的返回结果是/?page=2

6. 静态文件

静态文件:包括网页使用到的图片,JavaScript源码文件和CSS。
默认设置下,Flask 在程序根目录中名为 static 的子目录中寻找静态文件。

上一篇下一篇

猜你喜欢

热点阅读