Flask 入门系列教程(三)

  • A+
所属分类:安全开发

在通常的 Web 程序中,访问一个 URL 地址,一般都会返回一个 HTML 页面,而我们的数据就是嵌套在这些 HTML 代码当中的,再辅以 JavaScript 和 CSS 等,就组成了一个完整的前端页面了。

当然,对于 Flask 来说,它所包含的 HTML 页面还会包含一些变量和逻辑运算等代码,这些组合到一起就是模板。执行这些变量替换和逻辑计算工作的过程被称为渲染,这个工作由 Flask 自带的模板渲染引擎——Jinja2 来完成。

按照默认的设置,Flask 会从程序实例所在模块同级目录的 templates 文件夹中寻找模板,所以我们可以在 app.py 文件的同级目录下创建一个 templates 文件夹,用来存储模板文件。

下面我们先来简单熟悉下 Flask 模板的用法

模板基本语法

我们先来看一段例子,下面是 HTML 代码中嵌套了 Jinja2 的控制语法

<h1>{{ username }}的 Web 网站</h1>
{% if auth %}
<p>{{ admin }}</p>
{% else %}
<p>陌生人</p>
{% endif %} {# 大部分 Jinja 语句都需要声明关闭 #}

模板基本的三种定界符
{{ … }} 用来标记变量。比如在上例中就可以渲染出 username 所对应的具体数据

{% … %} 用来标记语句,比如 if 语句,for 语句等。例子中的 if…else… 语句就是简单的判断

{# … #} 用来写注释。

在 Jinja2 中允许我们使用大部分 Python 对象,比如字符串、列 表、字典、元组、整型、浮点型、布尔值。它支持基本的运算符号 (+、-、*、/等)、比较符号(比如==、!=等)、逻辑符号(and、 or、not和括号)以及in、is、None和布尔值(True、False)。

渲染模板

我们一般使用 Flask 提供的渲染函数 render_template() 来渲染模板

from flask import render_template 
@app.route('/test') 
def test():    
    name = 'admin'
    return render_template('test.html', user=name)

render_template 函数第一个参数为模板文件名,一般会在 templates 目录下寻找。还可以以关键字参数的形式传入变量到模板,这样在模板中就可以使用 user 这个变量了,其变量值为 ‘admin’。
下面我们就把上一节中在视图函数中书写的 HTML 代码整理到对应的模板中

整理模板

对于 needLogin1 页面,我们原来的视图函数是

@app.route('/needlogin1/')
def needLogin1():
    if 'loginID' in session:
        return '<h1>Hello, needLogin1!</h1>'
    else:
        return """
            <h1>Login</h1><a href="%s">Go To Login</a>
                """
 % url_for('login', next=request.url)

我们可以分别在 templates 创建两个文件,hello.html 和 needlogin.html
对于 hello.html 文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Web</title>
</head>
<body>
<h1>Hello, {{ user }}!</h1>
</body>
</html>

对于 needlogin.html 文件

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>My Web</title>
</head>
<body>
<h1>Login</h1><a href="{{ url_for('login', next=request.url) }}">Go To Login</a>
</body>
</html>

接着我们再改写视图函数 needLogin1

@app.route('/needlogin1/')
def needLogin1():
    if 'loginID' in session:
        user = 'needLogin1'
        return render_template('hello.html', user=user)
    else:
        return render_template('needlogin.html')

这部分代码可以检出代码3a来查看

链接

在上面 needlogin.html 文件中你应该发现了,对于 href 属性,我们使用了 url_for() 这个函数来获取 URL 链接,这是和前面讲解的视图函数中 url_for 非常相似的。

url_for() 函数最简单的用法是以视图函数名作为参数,返回对应的 URL。当然还是像例子中展示的那样,传递额外的参数到查询字符串中 url_for('login', next=request.url)。

变量与结构控制

在前面我们简单实践了 Flask 模板的变量与结构控制的用法,下面我们来详细说明下它们的功能

变量

在上面的例子中,我们使用了 {{ user }} 表示一个变量,它是一种特殊的占位符,告诉模板引擎这个位置的值需要从渲染模板时使用的数据中获取。

Jinja2 可以识别很多复杂的变量类型,比如列表、字典,对象等。

<p>这是字典: {{ mydict['key'] }}.</p> 
<p>这是列表: {{ mylist[3] }}.</p> 
<p>可变索引的列表: {{ mylist[myindex] }}.</p> 
<p>调用方法: {{ myobj.somemethod() }}.</p>

还可以使用一些过滤器,来修改变量,从而达到快速处理数据的效果。过滤器名添加在变量名之后,中间使用竖线分隔。

{{ name|title }} # 把变量name标题化

一些常用的过滤器

过滤器 说明
safe 渲染值时不转义
capitalize 首字母大写,其余字母小写
lower 转换成小写
upper 转换成大写
trim 去掉首尾空格
escape 转义 HTML 文本
default 设置默认值

这里我们着重说一下 safe 过滤器,默认情况下,Jinja2 会转义所有 HTML 标签,比如如果传<h1>你好</h1>,会被渲染成”<hi>你好</h1>“,此时浏览器就会把 <h1> 标签当作时一个普通字符来展示。而当我们需要把变量按照 HTML 代码来展示时,就可以使用 safe 过滤器

{{ "<h1>你好</h1>"|safe }}

控制结构

我们常用的控制结构有两种,即 for 循环和 if 判断。下面是这两种控制结构的例子

if 判断
{% if user %}     
Hello, {{ user }}! 
{% else %}     
Hello, Stranger! 
{% endif %}
# for 循环
{% for user in users %}         
<li>{{ user }}</li>     
{% endfor %} 

模板继承

模板的继承类似于 Python 中的继承,即我们可以把页面上的一些通用原始编写到基模板中,然后其他子模版只需要编写对应页面特殊的代码即可,其他比如导航栏,页脚等内容可以放到基模板中编写。

先来编写基模板,base.html

<html> 
<head>     
{% block head %}     
<title>{% block title %}{% endblock %} - My Web</title>     
{% endblock %} 
</head> 
<body>     
{% block body %}     
{% endblock %} 
</body> 
</html>

在基模板中,我们用 block 来标记需要替换的部分,在上面的例子中我们定义了 head、title 和 body 块,那么子模版就可以任意修改这三块内容了
编写子模板,我们创建一个 user.html 模板

{% extends "base.html" %} 
{% block title %}User{% endblock %} 
{% block head %}     
{{ super() }}     
<style>     
</style> 
{% endblock %} 
{% block body %} 
<h1>Hello, World!</h1> 
{% endblock %}

使用 extends 来引入基模板,之后再重新定义3个 block 块。这里需要注意 super 的使用,如果在子模板中没有 super,那么子模板会覆盖基模板中的内容,如果添加了 super,就是追加内容,即对应的 block 块中会包含基模板的内容。

集成  Bootstrap

Bootstrap 是 Twitter 开发一个开源框架,他有许多可用的界面组件,可以帮助我们快速的搭建前端页面。当然要集成  Bootstrap 框架,我们就需要对模板进行相关的改动,而这些完全可用交给插件 Flask-Bootstrap 来完成。

pip install flask-bootstrap # 安装插件

在 Flask app 中初始化  Flask-Bootstrap

from flask_bootstrap import Bootstrap
...
bootstrap = Bootstrap(app)

初始化 Flask-Bootstrap 之后,就可以在程序中使用一个包含所有 Bootstrap 文件的基模板。这个模板利用 Jinja2 的模板继承机制,让程序扩展一个具有基本页面结构的基模板。

完善程序

下面我们就把前面写的模板通过 bootstrap 来优化下,首先是基模板,包含通用的导航栏

{% extends "bootstrap/base.html" %} 

{% block title %}My Web{% endblock %}{% block navbar %}
<div class="navbar navbar-default navbar-static-top" role="navigation">
        <div class="container">
            <div class="navbar-header">
                <button class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> <span class="icon icon-bar"></span> <span class="icon icon-bar"></span> <span class="icon icon-bar"></span> </button>
                <a href="#" class="navbar-brand">HelloFlask</a>
            </div>
            <div class="collapse navbar-collapse">
                <ul class="nav navbar-nav navbar-right">
                    <li><a href="#home" class="smoothScroll">首页</a></li>
                    <li><a href="#intro" class="smoothScroll">网站简介</a></li>
                    <li><a href="#team" class="smoothScroll">风格</a></li>
                    <li><a href="#portfolio" class="smoothScroll">作品</a></li>
                    <li><a href="#contact" class="smoothScroll">联系我们</a></li>
                </ul>
            </div>
        </div>
    </div>
{% endblock %}{% block content %}
<div class="container">
    {% block page_content %}{% endblock %}
</div> {% endblock %}

接下来我们在 hello.html 模板上继承该基模板,并查看效果

{% extends "base.html" %}
{% block title %}My Web - Index{% endblock %}{% block page_content %}
<div class="page-header">
    <h1>Hello, {{ user }}!</h1>
</div> 
{% endblock %}

刷新页面,可以看到现在的页面如下

Flask 入门系列教程(三)


添加 Favicon

Favicon 是网站的特殊标记,可以展示在收藏夹、浏览器标签中的图标。现在我们就为我们的网站添加一个 Favicon。

首先我们在 templates 文件夹的同级目录上创建一个 static 文件夹,然后在使用一些在线工具制作 favicon.ico 文件,并放置到该目录下

在线转换工具有很多,可以使用这个

http://www.faviconico.org/favicon

最后我们在 HTML 页面中声明 Favicon 的路径,在 base.html 模板中的  标签中添加一个

<head>
{% block head%}
    {{ super() }}
    <meta charset="utf-8">
    <title>
    {% block title %}My Web{% endblock %}
    </title>
    <link rel="icon" type="image/x-icon" href="{{ url_for('static', filename='favicon.ico')}}">
{% endblock %}
</head>

消息闪现

Flask 还提供了一个非常有用的函数 flash(),它可以在页面上闪现需要展示给用户的消息。它的工作原理就是把相关的信息存储在浏览器的 session 中,然后我们在模板中使用全局函数 get_flashed_messages() 获取消息并将其显示出来。

下面我们对登陆成功的用户闪现消息,先在登陆视图函数中添加 flash

@app.route('/login/')
def login():
    session['loginID'] = 'admin'
    target = request.args.get('next')
    flash(u"你登陆成功了!")
    if check_next(target):
        return redirect(target)
    return redirect(url_for('hello'))

然后再在 hello.html 模板中渲染 flash 消息

{% extends "base.html" %}{% block title %}My Web - Index{% endblock %}{% block page_content %}{% for message in get_flashed_messages() %}
 <div class
="alert alert-warning">
     <button type="button" class="close" data-dismiss="alert">&times;</button>
     {{ message }}
 </div>
{% endfor %}
<div class="page-header">
    <h1>Hello, {{ user }}!</h1>
</div>
{% endblock %}

最终的效果

Flask 入门系列教程(三)


这部分的代码,可以检出代码库中的 3b

总结

本节我们学习了 Flask 中模板的使用,这对于我们快速完成 Web 应用开发是非常方便的。

Flask 入门系列教程(三)



发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: