欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【Flask学习笔记】模板(二)

程序员文章站 2022-05-20 23:38:21
...

flask 使用 jinjia2 模板引擎,为了便于使用,已经集成到 render_template 函数中,可以直接调用。模板引擎实现对模板的渲染,就是根据上下文,对模板中的占位变量,用真实值替换,形成最终的响应文件。

默认情况下,Flask 在程序文件夹中的 templates 子文件夹中寻找模板。

 

(一)模板的调用

demo.py文件代码如下:

from flask import Flask
from flask import render_template
app = Flask(__name__)

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

注意:render_template中是包含 .html 后缀的完整文件名 

index.html文件代码如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<h1>hello world!</h1>
</body>
</html>

 执行demo.py后,浏览器访问地址:http://127.0.0.1:5000/,页面显示“hello world”。

这就完成了简单的一次模板调用。

(二)模板的传参

#模板传参
@app.route('/user/<xiao>')
def user(xiao):
    return render_template("xiao.html",xiao=xiao)

  第一个参数是模板的名称,然后是 键/值 对,xiao=xiao左边表示模板中的占位符,右边是当前视图中的变量。意思是,将当前视图中变量xiao的值,赋值给模板中名为xiao的占位符,用于渲染。

xiao.html代码如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
传递参数:{{ xiao }}
</body>
</html>

 执行后,浏览器访问地址:http://127.0.0.1:5000/user/<xiao>,其中“<xiao>”为变量,需要手动赋值。

若是:http://127.0.0.1:5000/user/123,则显示“传递参数:123”

若是:http://127.0.0.1:5000/user/abc,则显示“传递参数:abc”

 

(三)模板的变量传参

@app.route('/test')
def hello_world():
    centent="调用的hello_world()函数里面的centent"
    return render_template("test.html",centent=centent)

 第一个参数是模板的名称,然后是 键/值 对,centent=centent左边表示模板中的占位符,右边是当前视图中的变量。意思是,将当前视图中变量centent的值,赋值给模板中名为centent的占位符,用于渲染。

test.html代码如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
   调用的参数为: {{ centent }}
</body>
</html>

  执行后,浏览器访问地址:http://127.0.0.1:5000/user/test,返回结果为:"调用的参数为: 调用的hello_world()函数里面的centent"

  • 表示

{{ name }}

占位符,告诉模板引擎,这个位置的值从渲染模板时传递的数据字典中获取

  • 支持的变量类型

支持所有类型,字符串、整型、列表、字典 ......

  • 修改显示样式

通过使用过滤器,可以定制 变量的值 显示的效果,比如 大小写。{{ name | 过滤器 }}

过滤器列表

  • 模板变量

在模板中设置模板变量

 

{% set name = 'john' %}

 

(四)模板的相对复杂的对象传递

 

 

Jinja2变量过滤器
过滤器名 说  明
safe 渲染值时不转义
capitalize 把值得首字母转为大写,其它字母转为小写
lower 把值转换成小写形式
upper 把值转换成大写形式
title 把值中每个单词的首字母转换成大写
trim 把值得首尾空格去掉
striptags 渲染之前把值中所有的HTML标签都删掉

safe 过滤器值得特别说明一下。默认情况下,出于安全考虑,Jinja2 会转义所有变量。例

如,如果一个变量的值为 '<h1>Hello</h1>' ,Jinja2 会将其渲染成 '&lt;h1&gt;Hello&lt;/

h1&gt;' ,浏览器能显示这个 h1 元素,但不会进行解释。很多情况下需要显示变量中存储

的 HTML 代码,这时就可使用 safe 过滤器。

千万别在不可信的值上使用 safe 过滤器,例如用户在表单中输入的文本。

完整的过滤器列表可在 Jinja2 文档(http://jinja.pocoo.org/docs/templates/#builtin-filters)中

查看。

新建modes.py文件,代码如下:

#创建一个User类,用来存放users
class User(object):
    #定义两个字段,一个user_id,一个user_name
    def __init__(self,user_id,user_name):

        self.user_id=user_id
        self.user_name=user_name

 demo.py文件代码如下:

#coding:utf-8
from flask import Flask
from flask import render_template
from modes import  User
app = Flask(__name__)

#传递一个name对象
@app.route('/name')
def name():
    user=User(1,"xiaojingjing")
    return render_template("user_index.html",user=user)

if __name__ == '__main__':
    app.run()

 user_index.html文件代码如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
   你好! {{ user.user_name }}
</body>
</html>

 执行后,浏览器访问地址:http://127.0.0.1:5000/name,返回结果为:"你好! xiaojingjing"

(五)控制语句  if  else 判断

 

demo.py文件代码如下:

#控制语句,if else 判断
@app.route('/user_name/<user_id>')
def user_name(user_id):
    user=None
    if int(user_id)==1:
        user=User(1,'xiaojingjing')
    # else:
    #     return "Sorry,no this user"
    return render_template("user_id.html",user=user)

 user_id.html文件代码如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
{% if user %}
你好,{{ user.user_name }}!
{% else %}
    no this user
{% endif %}
</body>
</html>

  执行后,浏览器访问地址:http://127.0.0.1:5000/user_name/1,返回结果为:"你好! xiaojingjing"

 执行后,若浏览器访问地址:http://127.0.0.1:5000/user_name/2,返回结果为:"no this user"

 

(六)控制语句 for循环

demo.py文件代码如下:

#控制语句,for循环
@app.route('/user_list')
def user_list():
    users=[]
    for i in range(1,11):
        user=User(i,"小白"+str(i))
        users.append(user)
    return  render_template("user_list.html",users=users)

 user_list.html文件代码如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
{% for user in users %}
    {{ user.user_id }}--{{ user.user_name }}<br>
{% endfor %}
</body>
</html>

   执行后,浏览器访问地址:http://127.0.0.1:5000/user_list,

返回结果为:

"1--小白1
2--小白2
3--小白3
4--小白4
5--小白5
6--小白6
7--小白7
8--小白8
9--小白9
10--小白10"

 

(七)继承

如果多个页面的大部分内容相同,可以定义一个母模板,包含相同的内容,然后子模板继承内容,并根据需要进行部分修改

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

 PS:模板里面,不能同时有两个{% extends " " %}语句,即使另一个被注释了也不行

如果多个网页中都有一段内容相同,可以将相同的内容放入一个文件中comments.html,通过include导入

{% include 'comments.html' %}

 

首先,创建一个基类

base.html文件,代码如下:

<html lang="en">
<head>
    <meta charset="UTF-8">
    <title></title>
</head>
<body>
<div>
    <h1>top部分</h1>
</div>
{% block content %}
{% endblock %}

<div>
    <h1>底部部分</h1>
</div>
</body>
</html>

 one_base.html文件,代码如下:

{% extends "base.html" %}
{% block content%}
    这是第一页
{% endblock %}

 two_base.html文件,代码如下:

{% extends "base.html" %}
{% block content%}
    这是第二页
{% endblock %}

 然后到demo再新定义两个路由,代码如下:

#模板的继承

@app.route('/one_base')
def one_base():
    return render_template("one_base.html")

@app.route('/two_base')
def two_base():
    return render_template("two_base.html")

 执行后,浏览器访问地址:“http://127.0.0.1:5000/one_base” 和“http://127.0.0.1:5000/two_base”

 

--------------待补充:

宏:macro...endmacro

类似函数

 

定义一个宏,指定宏的名称、参数,调用

 

{% macro x(y) %}
    ...
{% endmacro %}

{{ x(y) }}

 如果需要在多个模板中复用,可以将宏的定义放入一个文件,‘macro.html’

{% macro x(y) %}
    ...
{% endmacro %}

 然后导入使用

import 'macro.html' as macro

{{ macro.x(y) }}

 

 

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')