Flask模板

2020-01-16 12:33:51 浏览数 (1)

模板基本语法

代码语言:javascript复制
{% if user %}
    {{ user }}
{% else %}
    hello!
<ul>
    {% for index in indexs %}
    <li> {{ index }} </li>
    {% endfor %}
</ul>

一 变量

在模板中{{ variable }}结构表示变量,是一种特殊的占位符,告诉模板引擎这个位置的值,从渲染模板时使用的数据中获取;Jinja2除了能识别基本类型的变量,还能识别{};

视图:

代码语言:javascript复制
from flask import Flask, render_template

app = Flask(__name__)


@app.route("/index")
def index():
    data = {
        "name": "test",
        "size": 11,
        "adict": {"title": "index"},
        "alist": [1,2,3,4,5,6]
    }
    return render_template('index.html', **data)
    # return render_template("index.html", name="tile")


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

View Code

模板:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta http-equiv='Content-type' content='text/htm'>
</head>
<body>
<p>name---{{ name }}</p>
<p>size---{{ size }}</p>
<p>adict---title:{{ adict["title"] }}</p>
<p>adict---title:{{ adict.title }}</p>
<p>alist---{{ alist }}</p>
<p>alist---:alist[0]:{{ alist[0] }}</p>
<p>alist---:alist[2]:{{ alist.2 }}</p>
<p>alist---:alist[0] alist[1]:{{ alist[0]   alist[1] }}</p>
<p>{{ "hello"   "flask" }}</p>
</body>
</html>

View Code

自定义错误页面:

代码语言:javascript复制
@app.errorhandler(404)
def page_not_found(e):
    return render_template('404.html'), 404

View Code

二 过滤器

过滤器的本质就是函数。有时候我们不仅仅只是需要输出变量的值,我们还需要修改变量的显示,甚至格式化、运算等等,这就用到了过滤器。 过滤器的使用方式为:变量名 | 过滤器。 过滤器名写在变量名后面,中间用 | 分隔。如:{{variable | capitalize}},这个过滤器的作用:把变量variable的值的首字母转换为大写,其他字母转换为小写。 其他常用过滤器如下:

2.1 字符串过滤器:

代码语言:javascript复制
safe:禁用转义;
  <p>{{ '<em>hello</em>' | safe }}</p>

capitalize:把变量值的首字母转成大写,其余字母转小写;
  <p>{{ 'hello' | capitalize }}</p>

lower:把值转成小写;
  <p>{{ 'HELLO' | lower }}</p>

upper:把值转成大写;
  <p>{{ 'hello' | upper }}</p>

title:把值中的每个单词的首字母都转成大写;
  <p>{{ 'hello' | title }}</p>

trim:把值的首尾空格去掉;
  <p>{{ ' hello world ' | trim }}</p>

reverse:字符串反转;
  <p>{{ 'olleh' | reverse }}</p>

format:格式化输出;
  <p>{{ '%s is %d' | format('name',17) }}</p>

striptags:渲染之前把值中所有的HTML标签都删掉;
  <p>{{ '<em>hello</em>' | striptags }}</p>

2.2 支持链式使用过滤器

代码语言:javascript复制
<p>{{ “ hello world  “ | trim | upper }}</p>

2.3 列表过滤器

代码语言:javascript复制
first:取第一个元素
  <p>{{ [1,2,3,4,5,6] | first }}</p>

last:取最后一个元素
  <p>{{ [1,2,3,4,5,6] | last }}</p>

length:获取列表长度
  <p>{{ [1,2,3,4,5,6] | length }}</p>

sum:列表求和
  <p>{{ [1,2,3,4,5,6] | sum }}</p>

sort:列表排序
  <p>{{ [6,2,3,1,5,4] | sort }}</p>

2.4 语句块过滤

代码语言:javascript复制
{% filter upper %}
    this is a Flask Jinja2 introduction
  {% endfilter %}

2.5 自定义过滤器:

过滤器的本质是函数。当模板内置的过滤器不能满足需求,可以自定义过滤器。自定义过滤器有两种实现方式:一种是通过Flask应用对象的add_template_filter方法。还可以通过装饰器来实现自定义过滤器。

自定义的过滤器名称如果和内置的过滤器重名,会覆盖内置的过滤器。

实现方式一:通过调用应用程序实例的add_template_filter方法实现自定义过滤器。该方法第一个参数是函数名,第二个参数是自定义的过滤器名称。

代码语言:javascript复制
def list_step_2(li):
    """自定义过滤器"""
    return li[::2]

# 注册过滤器
app.add_template_filter(list_step_2, "li2")

View Code

实现方式二:用装饰器来实现自定义过滤器。装饰器传入的参数是自定义的过滤器名称。

代码语言:javascript复制
@app.template_filter("li3")
def list_step_3(li):
    """自定义过滤器"""
    return li[::3]

View Code

三 Web表单:

web表单是web应用程序的基本功能。

它是HTML页面中负责数据采集的部件。表单有三个部分组成:表单标签、表单域、表单按钮。表单允许用户输入数据,负责HTML页面数据采集,通过表单将用户输入的数据提交给服务器。

在Flask中,为了处理web表单,我们一般使用Flask-WTF扩展,它封装了WTForms,并且它有验证表单数据的功能。

WTForms支持的HTML标准字段

字段对象

说明

StringField

文本字段

TextAreaField

多行文本字段

PasswordField

密码文本字段

HiddenField

隐藏文本字段

DateField

文本字段,值为datetime.date格式

DateTimeField

文本字段,值为datetime.datetime格式

IntegerField

文本字段,值为整数

DecimalField

文本字段,值为decimal.Decimal

FloatField

文本字段,值为浮点数

BooleanField

复选框,值为True和False

RadioField

一组单选框

SelectField

下拉列表

SelectMultipleField

下拉列表,可选择多个值

FileField

文本上传字段

SubmitField

表单提交按钮

FormField

把表单作为字段嵌入另一个表单

FieldList

一组指定类型的字段

WTForms常用验证函数

验证函数

说明

DataRequired

确保字段中有数据

EqualTo

比较两个字段的值,常用于比较两次密码输入

Length

验证输入的字符串长度

NumberRange

验证输入的值在数字范围内

URL

验证URL

AnyOf

验证输入值在可选列表中

NoneOf

验证输入值不在可选列表中

使用Flask-WTF需要配置参数SECRET_KEY。

CSRF_ENABLED是为了CSRF(跨站请求伪造)保护。 SECRET_KEY用来生成加密令牌,当CSRF激活的时候,该设置会根据设置的密匙生成加密令牌。

在HTML页面中直接写form表单:

代码语言:javascript复制
#模板文件
<form method='post'>
    <input type="text" name="username" placeholder='Username'>
    <input type="password" name="password" placeholder='password'>
    <input type="submit">
</form>

View Code

视图函数中获取表单数据:

代码语言:javascript复制
from flask import Flask,render_template,request

@app.route('/login',methods=['GET','POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        print username,password
    return render_template('login.html',method=request.method)

View Code

使用Flask-WTF实现表单。

代码语言:javascript复制
pip install Flask-WTF

配置参数:

代码语言:javascript复制
app.config['SECRET_KEY'] = '.........'

模板页面:

代码语言:javascript复制
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta http-equiv='Content-type' content='text/htm'>
</head>
<body>
<form method="post">
    {{ reg_form.csrf_token }}
{{ reg_form.username.label }}
<p>{{ reg_form.username }}</p>
{{ reg_form.username.errors.0 }}

{{ reg_form.password.label }}
<p>{{ reg_form.password }}</p>
{{ reg_form.password.errors.0 }}

{{ reg_form.repassword.label }}
<p>{{ reg_form.repassword }}</p>
{{ reg_form.repassword.errors.0 }}
<br>
{{ reg_form.submit }}
</form>

</body>
</html>

View Code

视图函数:

代码语言:javascript复制
from flask import Flask, render_template, url_for, redirect, session
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, SubmitField
from wtforms.validators import DataRequired, EqualTo
app = Flask(__name__)

app.config["SECRET_KEY"] = "ada898u2q11joloadad02"

class RegiterForm(FlaskForm):
    username = StringField(label="用户名", validators=[DataRequired("用户名不能为空")])
    password = PasswordField(label="密码", validators=[DataRequired("密码不能为空")])
    repassword = PasswordField(label="确认密码", validators=[DataRequired("确认密码不能为空"), EqualTo("password", "两次密码输入不一致")])
    submit = SubmitField(label="提交")


@app.route("/register", methods=['GET', "POST"])
def register():
    # 创建表单对象, 如果是post请求, 前端发送了数据,flask会把数据在构造form对象的数据,存在对象中
    reg_form = RegiterForm()

    # 判断form中的数据是否合法
    if reg_form.validate_on_submit():
        username = reg_form.username.data
        password = reg_form.password.data
        repassword = reg_form.repassword.data

        session["username"] = username

        print(username, password, repassword)
        return redirect(url_for("index"))
    return render_template('register.html', reg_form=reg_form)


@app.route("/index")
def index():
    username = session.get("username")
    return "hello %s " % username


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

View Code

四 控制语句

4.1 if控制语句

代码语言:javascript复制
@app.route('/user')
def user():
    user = 'wusong'
    return render_template('user.html',user=user)

View Code

代码语言:javascript复制
 <html>
 <head>
     {% if user %}
        <title> hello {{user}} </title>
    {% else %}
         <title> welcome to flask </title>        
    {% endif %}
 </head>
 <body>
     <h1>hello world</h1>
 </body>
 </html>

View Code

4.2 for循环语句

代码语言:javascript复制
 @app.route('/loop')
 def loop():
    fruit = ['apple','orange','pear','grape']
    return render_template('loop.html',fruit=fruit)

View Code

代码语言:javascript复制
<html>
 <head>
     {% if user %}
        <title> hello {{user}} </title>
    {% else %}
         <title> welcome to flask </title>        
    {% endif %}
 </head>
 <body>
     <h1>hello world</h1>
    <ul>
        {% for index in fruit %}
            <li>{{ index }}</li>
        {% endfor %}
    </ul>
 </body>
 </html>

View Code

五 宏、继承、包含

类似于python中的函数,宏的作用就是在模板中重复利用代码,避免代码冗余。

Jinja2支持宏,还可以导入宏,需要在多处重复使用的模板代码片段可以写入单独的文件,再包含在所有模板中,以避免重复。

5.1 宏

定义宏

代码语言:javascript复制
{% macro input() %}
<input type="text" name="username" value="">
{% endmacro %}

调用宏

代码语言:javascript复制
{{ input() }}

定义带参数的宏

代码语言:javascript复制
{% macro input1(name, value="", type="text") %}
<input type="{{ type }}" name="{{ name }}" value="{{ value }}">
{% endmacro %}

调用宏,并传递参数

代码语言:javascript复制
{{ input1(pwd, type="password") }}

把宏单独抽取出来,封装成html文件,其它模板中导入使用

文件名可以自定义macro_input.html

代码语言:javascript复制
{% macro function() %}

    <input type="text" name="username" placeholde="Username">
    <input type="password" name="password" placeholde="Password">
    <input type="submit">
{% endmacro %}

在其它模板文件中先导入,再调用

代码语言:javascript复制
{% import 'macro_input.html' as func %}
{{ func.function() }}

5.2模板继承

模板继承是为了重用模板中的公共内容。一般Web开发中,继承主要使用在网站的顶部菜单、底部。这些内容可以定义在父模板中,子模板直接继承,而不需要重复书写。

{% block top %}.......{% endblock %}标签定义的内容,相当于在父模板中挖个坑,当子模板继承父模板时,可以进行填充。

父模板:base.html

代码语言:javascript复制
{% block top %}
    顶部菜单
  {% endblock top %}

  {% block content %}
  {% endblock content %}

  {% block bottom %}
    底部
  {% endblock bottom %}

子模板:

代码语言:javascript复制
{% extends 'base.html' %}
  {% block content %}
   需要填充的内容
  {% endblock content %}

模板继承使用时注意点:

  • 不支持多继承。
  • 为了便于阅读,在子模板中使用extends时,尽量写在模板的第一行。
  • 不能在一个模板文件中定义多个相同名字的block标签。
  • 当在页面中使用多个block标签时,建议给结束标签起个名字,当多个block嵌套时,阅读性更好。

5.3包含(Include)

Jinja2模板中,除了宏和继承,还支持一种代码重用的功能,叫包含(Include)。它的功能是将另一个模板整个加载到当前模板中,并直接渲染。

示例:

include的使用

代码语言:javascript复制
{% include 'hello.html' %}

包含在使用时,如果包含的模板文件不存在时,程序会抛出TemplateNotFound异常,可以加上ignore missing关键字。如果包含的模板文件不存在,会忽略这条include语句。

示例:

include的使用加上关键字ignore missing

代码语言:javascript复制
{% include 'hello.html' ignore missing %}
  • 宏、继承、包含:
    • 宏(Macro)、继承(Block)、包含(include)均能实现代码的复用。
    • 继承(Block)的本质是代码替换,一般用来实现多个页面中重复不变的区域。
    • 宏(Macro)的功能类似函数,可以传入参数,需要定义、调用。
    • 包含(include)是直接将目标模板文件整个渲染出来。

六 Flask中的特殊变量和方法

在Flask中,有一些特殊的变量和方法是可以在模板文件中直接访问的。

config 对象:

代码语言:javascript复制
config 对象就是Flask的config对象,也就是 app.config 对象。

{{ config.SQLALCHEMY_DATABASE_URI }}

request 对象:

就是 Flask 中表示当前请求的 request 对象,request对象中保存了一次HTTP请求的一切信息。

request常用的属性如下:

属性

说明

类型

data

记录请求的数据,并转换为字符串

*

form

记录请求中的表单数据

MultiDict

args

记录请求中的查询参数

MultiDict

cookies

记录请求中的cookie信息

Dict

headers

记录请求中的报文头

EnvironHeaders

method

记录请求使用的HTTP方法

GET/POST

url

记录请求的URL地址

string

files

记录请求上传的文件

*

代码语言:javascript复制
{{ request.url }}

url_for 方法:

url_for() 会返回传入的路由函数对应的URL,所谓路由函数就是被 app.route() 路由装饰器装饰的函数。如果我们定义的路由函数是带有参数的,则可以将这些参数作为命名参数传入。

代码语言:javascript复制
{{ url_for('index') }}

{{ url_for('post', post_id=1024) }}

get_flashed_messages方法:

返回之前在Flask中通过 flash() 传入的信息列表。把字符串对象表示的消息加入到一个消息队列中,然后通过调用 get_flashed_messages() 方法取出。

代码语言:javascript复制
{% for message in get_flashed_messages() %}
    {{ message }}
{% endfor %}

示例:

代码语言:javascript复制
from flask import Flask, render_template, flash

app = Flask(__name__)

app.config["SECRET_KEY"] = "diaj29u912kjwsle01sda"

flag = True

@app.route("/index")
def index():
    global flag
    if flag:
        flash("flash1")
        flash("flash2")
        flash("flash3")
        flag = False
    return render_template("index.html")


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

View Code

代码语言:javascript复制
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <meta http-equiv='Content-type' content='text/htm'>
</head>
<body>
<h1>闪现</h1>
{% for msg in get_flashed_messages() %}
{{ msg }}
{% endfor %}

</body>
</html>

View Code

0 人点赞