偷个懒,公号抠腚早报80%自动化——3.Flask速成大法(中)

简介: 本节就来过一过Flask,下一节再来利用Flask来写API接口和 静态页面,以及直接生成公号文章样式。

6、模板


在Web开发中,我们经常会用到模板引擎,什么是模板?就是一个包含响应文本的文件, 用占位符(变量)标识动态部分,告诉模板引擎,其具体值需要从使用的数据中获取


0x1 视图与模板的关系


在前面的例子中,视图函数的主要作用是生成请求的响应,而实际开发中,视图函数有 两个作用:「处理业务逻辑」和「返回响应内容」。在大型项目中,如果把业务逻辑 和表现内容放在一起的话,会增加代码的复杂度和维护成本。而模板的作用就是: 「承担视图函数返回响应内容这一部分的职责,从而使得代码结构清晰,耦合度低。」 使用真实值替换变量,再(控制)返回最终得到的字符串,这个过程称作「渲染」。 Flask中默认使用「Jinja2」这个模板引擎来渲染模板。


0x2 Jinja2语法


通过一个简单的例子,引入模板,下面是一个没有使用模板的简单程序:


# coding=utf-8
from flask import Flask
app = Flask(__name__)
@app.route("/<user>")
def hello(user):
    if user == 'admin':
        return "<h1>管理员,您好!<h1>"
    else:
        return "<h1>%s, 您好!</h1>" % user
if __name__ == "__main__":
    app.run()


接着我们使用Jinja2模板进行改写,默认情况下,Flask会在「项目的templates子文件夹」 中寻找模板,我们新建一个templates文件夹,然后新建一个index.html,内容如下:


"<h1>{{name}},您好!<h1>"


接着修改下hello.py文件,修改后的内容如下:


from flask import Flask, render_template
app = Flask(__name__)
@app.route("/<user>")
def hello(user):
    if user == 'admin':
        return render_template("index.html", user="管理员")
    else:
        return render_template("index.html", user=user)
if __name__ == "__main__":
    app.run()


接着运行hello.py,浏览器键入以下地址,对应输出结果如下:


http://127.0.0.1:5000/admin     # 输出结果:管理员,您好!
http://127.0.0.1:5000/jay       # 输出结果:jay,您好!


以上就是一个简单的模板使用示例,通过调用Flask提供的render_template函数, 生成了一个模板,第一个参数是模板的名称,随后的参数是键值对,表示模板中 变量对应的真实值。接着详细讲解一波Jinja2的语法:


1.变量


Jinja2使用**{{变量名}}**来表示一个变量,除了基本数据类型外还可以使用列表,字段 或对象等复杂类型,示例如下:


<h1> 账号:{{ user['name'] }},密码:{{ user['passwd'] }}


2.控制结构


Jinja2提供了多种控制结构,比如常见的判断和循环结构,用于修改模板的渲染流程。 我们把上面判断的逻辑也放到模板里,示例如下:


{# 注释,不会输出到浏览器中 #}
{% if user == 'admin' or user == '管理员' %}
    <h1> 管理员,您好! </h1>
{% else %}
    <h1> {{ user }},您好!</h1>
{% endif %}
{# 循环打印 #}
{% for num in num_list %}
    <h2>{{ num }}</h2>
{% endfor %}


接着修改下hello.py文件:


@app.route("/<user>")
def hello(user):
    return render_template("index.html", user=user, num_list=[1, 2, 3])


键入不同的URL,对应浏览器的输出结果如下:


http://127.0.0.1:5000/admin
管理员,您好!
1
2
3
http://127.0.0.1:5000/jay
jay,您好!
1
2
3


3.宏


在Python中如果有一些很常用的代码,我们会习惯性地抽取成一个函数,在Jinji2中, 可以使用宏来实现。语法如下:


# 创建宏
{% macro 标签名(key=value) %} 
    常用代码
{% end macro %}
# 调用宏
{{ 标签名(key=value) }}


如果宏比较多,可以抽到单独的HTML中,再import进来。


{% import 'xxx.html' as 别名 %}
{{ 别名.标签名(key=value) }}


4.模板继承


另一种代码复用的方式:模板继承,和Python中类继承一样,需要一个基模板,用{% block XXX %}{% endblock %} 标识一个代码块,可以在子模块中重载。 代码示例如下:


# 基模板:base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% block head %}
        <title>{% block title %} Title {% endblock %} </title>
    {% endblock %}
</head>
<body>
    {% block body %}
    {% endblock %}
</body>
</html>
# 子模板:son.html
{% extends "base.html" %}
{% block title %}Son{% endblock %}
{% block head %}
    {{ super() }}
{% endblock %}
{% block body %}
<h1>Hello Flask!</h1>
{% endblock %}


代码简述:


第一行代码使用extends命令,表明该模板继承自base.html,接着重写了title,head和 body代码块,上面的super()函数用于获取基模板原先的内容。


5.inclue


可以用include语句包含一个模板,在渲染时会把include语句对应位置添加被包含的模板, 使用示例如下:


{% include 'header.html' %}


另外还可以使用「ignore missing」标记,如果模板不存在,Jinja2会忽略此语句,示例如下:


{% include 'header.html' ignore missing %}


6.赋值


可以使用set标签来进行赋值,示例如下:


{% set a,b = 1,2}
<h1>{{ a }}{{ b }}</h1>


7.内建过滤器


过滤器的本质就是函数,有时需要修改,格式化或者执行变量间的计算,而在模板中是不能 直接调用Python中的某些方法的,可以用到过滤器。模板的过滤器支持链式调用:


{{ "hello flask" | reverse | upper}},


这串代码就是反转+转换成大写,常见的内建过滤器有字符串和列表两种。字符串操作过滤器如下表所示:


过滤器 描述
safe 禁用转义
capitalize 把变量值的首字母转成大写,其余字母转小写
lower 把值转成小写
upper 把值转成大写
title 把值中的每个单词的首字母都转成大写
reverse 字符串反转
format 格式化输出
striptags 渲染之前把值中所有的HTML标签都删掉
truncate 字符串截断


列表操作过滤器如下表所示:


过滤器 描述
first 取第一个元素
last 取最后一个元素
length 获取列表长度
sum 列表求和
sort 列表排序


8.自定义过滤器


直接在py文件中编写,代码示例如下:


# 1.定义过滤器
def do_listreverse(li):
    temp_li = list(li)
    temp_li.reverse()
    return temp_li
# 2.添加自定义过滤器
app.add_template_filter(do_listreverse, 'listreverse')


总结:


宏,继承和包含都用实现代码复用,宏功能类似于函数,可以传参,需要定义调用; 继承本质是代码替换,一般用来实现多个页面中重复不变的区域;而包含是直接将 目标模板文件整个渲染出来。


7、请求与相应


在Flask中,HTTP请求被封装成了Request对象,而HTTP响应则被封装成了Response对象。 因此Flask应用开发的逻辑处理,都是基于这两个对象。


0x1 Request请求


Flask会将WSGI服务器转发的http请求数据封装为一个Request对象,这个对象中包含了请求的 相关信息,可以通过下表中的属性来获取对应的信息。


属性 描述 数据类型
form 记录请求中的表单数据。 MultiDict
args 记录请求中的查询参数。 MultiDict
cookies 记录请求中的cookie。 Dict
headers 记录请求中的报文头。 EnvironHeaders
method 记录请求使用的HTTP方法。 string
environ 记录WSGI服务器转发的环境变量。 Dict
url 记录请求的URL地址。 string


1.读取request的查询参数


浏览器以GET请求的方式提交的表单数据,Flask会将其存储在request实例的args,也可以用values属性 来查询,读取代码示例如下:


# coding=utf-8
from flask import Flask, request, json
app = Flask(__name__)
@app.route("/index")
def index():
    return '''
           <form method="GET" action="/login">
               <input type="text" placeholder="账号" name="user"> <br />
               <input type="text" placeholder="密码" name="pawd"> <br />
               <input type="submit" value="登录">
           </form>
       '''
@app.route("/login")
def login():
    msg = ""
    if 'user' in request.args:
        msg += request.args['user'] + ':'
    msg += request.values.get('pawd','')
    return msg
if __name__ == "__main__":
    app.run(debug=True)


代码运行后,打开:http://127.0.0.1:5000/index,浏览器:



输入账号密码后,跳转到:http://127.0.0.1:5000/login?user=zpj&pawd=123, 浏览器:



2.读取request的表单数据


浏览器以GET请求的方式提交的表单数据,Flask会将其存储在request实例的form中,可以使用[]操作符 读取指定键值。读取代码示例如下:


# coding=utf-8
from flask import Flask, request, json
app = Flask(__name__)
@app.route("/index")
def index():
    return '''
           <form method="POST" action="/login">
               <input type="text" placeholder="账号" name="user"> <br />
               <input type="text" placeholder="密码" name="pawd"> <br />
               <input type="submit" value="登录">
           </form>
       '''
@app.route("/login", methods=['POST'])
def login():
    msg = ""
    msg += request.form['user'] + ':'
    msg += request.form['pawd']
    return msg
if __name__ == "__main__":
    app.run(debug=True)


代码运行后,打开:http://127.0.0.1:5000/index,浏览器:



输入账号密码后,跳转到:http://127.0.0.1:5000/login,浏览器:



0x2 Response响应


和Request对应,Response用于给浏览器发送响应信息,根据视图函数的返回结果。这个视图函数 就是我们路由下面的函数,视图函数的返回值会自动转换成一个响应对象,转换逻辑如下:


  • 1、返回值是合法的响应对象,从视图直接返回;


  • 2、返回值是字符串,会用字符串和默认参数创建以字符串为主体,返回码为200,MIME类型为 text/html的werkzeug.wrappers.Response响应对象。


  • 3、返回值是元组,其中的元素可以提供额外信息,但格式必须是(response,status,headers) 的形式,至少包含一个元素,status值会覆盖状态码,headers可以是字典或列表,作为额外的消息头。


  • 4、如果都不是,Flask会假设返回值是合法的WSGI程序,通过Response.force(rv.request.environ) 转换为一个请求对象。除了通过return方式返回,还可以显式地调用make_response函数返回,好处是可以 设置一些额外的信息,示例如下:


def hello():
    resp = make_response("Hello Flask!", 250)
    return resp


另外,现在的API接口都是返回JSON格式的,可以用jsonify包装下,修改后的示例代码如下:


# coding=utf-8
from flask import Flask, make_response, jsonify
from werkzeug.wrappers import Response
app = Flask(__name__)
@app.route("/", methods=['GET', 'POST'])
def hello():
    resp = make_response({'code': '200', 'msg': '请求成功', 'data': [{'data_1': ['数据', '数据'], 'data_2': ['数据', '数据']}]})
    return resp
class JsonResponse(Response):
    @classmethod
    def force_type(cls, response, environ=None):
        if isinstance(response, dict):
            response = jsonify(response)
        return super(JsonResponse, cls).force_type(response, environ)
app.response_class = JsonResponse
if __name__ == "__main__":
    app.run(debug=True)


请求接口输出如下:


{
    "code": "200",
    "data": [
        {
            "data_1": [
                "数据",
                "数据"
            ],
            "data_2": [
                "数据",
                "数据"
            ]
        }
    ],
    "msg": "请求成功"
}


也可以用Flask的json模块的dumps()函数将数组或字典对象转换为JSON字符串,代码示例如下:


data = {'code': '200', 'msg': '请求成功', 'data': [{'data_1': ['数据', '数据'], 'data_2': ['数据', '数据']}]}
return json.dumps(data),200,[('Content-Type','application/json;charset=utf-8')]


  • 3.设置CookieResponse类中提供了set_cookie()函数用于设置客户端的cookie,如果要设置cookie,需要我们自己构建Response实例 (通过make_response),可选参数如下:


set_cookie(
 key, //键
 value='', //值
 max_age=None, //秒为单位的cookie寿命,None表示http-only
 expires=None, //失效时间,datetime对象或unix时间戳
 path='/', //cookie的有效路径
 domain=None, //cookie的有效域
 secure=None, 
 httponly=False)


相关文章
|
存储 SQL 关系型数据库
偷个懒,公号抠腚早报80%自动化——3.Flask速成大法(下)
本节就来过一过Flask,下一节再来利用Flask来写API接口和 静态页面,以及直接生成公号文章样式。
111 0
|
API 网络架构 Python
偷个懒,公号抠腚早报80%自动化——3.Flask速成大法(上)
本节就来过一过Flask,下一节再来利用Flask来写API接口和 静态页面,以及直接生成公号文章样式。
136 0
|
编解码 计算机视觉 Python
|
计算机视觉 Python
|
22天前
|
运维 Ubuntu Devops
自动化运维工具的魅力:Ansible入门
【9月更文挑战第5天】在快速变化的IT世界里,自动化运维不再是可选项,而是必需品。Ansible,一款简单却强大的自动化工具,正成为众多DevOps工程师的首选。本文将带你了解Ansible的基本概念、安装步骤以及如何编写简单的Playbook,从而开启你的自动化之旅。
67 36
|
2天前
|
机器学习/深度学习 人工智能 运维
构建高效运维体系:从自动化到智能化的演进之路
在当今数字化时代,运维作为保障企业IT系统稳定运行的关键环节,正经历着前所未有的变革。本文将探讨如何通过实施自动化和引入智能化技术,构建一个更加高效、可靠的运维体系,以应对日益复杂的业务需求和技术挑战。
9 1
|
19天前
|
存储 弹性计算 运维
自动化监控和响应ECS系统事件
阿里云提供的ECS系统事件用于记录云资源信息,如实例启停、到期通知等。为实现自动化运维,如故障处理与动态调度,可使用云助手插件`ecs-tool-event`。该插件定时获取并转化ECS事件为日志存储,便于监控与响应,无需额外开发,适用于大规模集群管理。详情及示例可见链接文档。
|
12天前
|
机器学习/深度学习 运维 安全
构建高效运维体系:从自动化到智能化的演进之路
在数字化转型的浪潮中,运维管理作为信息技术基础设施的重要支柱,正经历着从传统手工操作向自动化、智能化的深刻变革。本文将探讨如何通过引入自动化工具和平台,实现运维流程的标准化与效率提升;进而利用大数据分析和人工智能技术,迈向预测性维护和智能决策支持的高级阶段。通过案例分析,揭示成功转型的关键因素,为运维专业人士提供一套可借鉴的升级路径。
|
10天前
|
机器学习/深度学习 人工智能 运维
构建高效运维体系:从自动化到智能化的演进之旅
在当今数字化时代,运维作为信息技术领域的核心组成部分,其重要性日益凸显。随着企业业务的不断扩展和技术的日新月异,传统手工运维方式已难以满足现代IT架构的需求。因此,构建一个高效、智能的运维体系成为业界共识。本文将探讨如何通过自动化和智能化手段,实现运维效率的质的飞跃,并分享一些成功案例与实践经验。