【自动化运维新手村】初见Flask

1,098 阅读8分钟

【摘要】

在Web框架序篇中,主要分析了一下Flask和Django各自的适用场景,最终的结论是,更倾向于推荐大家使用Flask,所以接下来的专题内容都会围绕Flask进行展开。

当然,讲解的风格仍然是延续我们一直以来秉承的思想,那就是从场景出发,先学习迫切需要用到的那部分知识,用不到的先不学,最近还新造了一个词叫最小化上手范围(Minimize Range),就是指想要完成一个需求所需要的最小化的知识范围。

现在正式开始Flask的讲解

【Flask】

Flask作为一个轻量级Web框架,那就先发挥一下他”轻“的优势,我们快速与之前的CMDB专题进行结合,抛弃掉原先通过命令行对数据源进行增删改查的方式,而是通过API请求来进行操作。

一、启动Flask

启动Flask的代码其实只需要几行(是真的几行),如下:

# app.py
from flask import Flask

app = Flask(__name__)

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

先在环境中安装好Flask的第三方包,通常执行pip install flask即可,之后就可以在命令行输入python app.py启动Flask项目。

启动之后的输出如下:

在这里插入图片描述

这里的输出一共有六行,就包括了五个知识点,但这里只讲最后两个,其他在番外篇和后续的章节中会讲到(因为暂时用不到)。

Running on http://127.0.0.1:5000/这行表示Flask应用此时已经监听了本地的127.0.0.1地址和5000端口

在这里插入图片描述

通过app.run()函数的参数注释可以看出,该函数接受的前两个参数分别是hostport,当没有传这两个参数的时候默认值设为127.0.0.15000

现在已经可以通过浏览器对这个网址进行访问了,但打开浏览器输入上述网址之后页面如下:

在这里插入图片描述

Not Found是HTTP状态码中的404错误,表示访问的链接资源不存在。这是因为我们只是启动了一个后端应用并监听了一个socket,并没有定义任何路由函数。

二、新增路由

现在新增部分代码如下:

# app.py
from flask import Flask

app = Flask(__name__)

@app.route("/")
def index():
    return "hello world"

if __name__ == "__main__":
    app.run(debug=True)

正常在修改代码之后需要停止程序并重新启动,但通过传入debug参数,可以在保存代码后动态加载让改动直接生效。

刷新页面后如下:

在这里插入图片描述

这里的@app.route("/")是Python中的装饰器语法,关于装饰器的详解,后续会在番外篇中提到,大家暂时只需要了解在一个普通的函数上面加上一行@app.route会把该函数注册到Flask到路由中,而app.route("/")传的参数就是URL中去掉IP和端口号之后的Path路径。 Flask的路由大家可以理解为一个字典,保存了Path对应的函数,这样当通过URL访问Flask后端应用的时候,就可以根据URL的Path找到对应函数去调用,然后返回数据。

三、结合CMDB

现在,将之前的CMDB代码cmdb.py以及数据文件data.json,放在app.py同级目录下,按照第二步的方式就可以新增几个路由分别对应CDMB的增删改查功能。

首先在cmdb.py中新增一个函数,能够让Flask调用到CMDB的实例对象,如下所示

# cmdb.py
def cmdb_handler():
    try:
        file_store = Store("file", "data.json")  # 实例化一个文件存储的存储对象
        cmdb = CMDB(file_store)  # 传入读出的数据源实例化一个CMDB的对象
        return cmdb
    except Exception as e:
        raise Exception("get cmdb handler failed, err: %s" % str(e))

app.py中导入创建CMDB实例对象的函数

# app.py
from flask import Flask
from cmdb import cmdb_handler

CMDB = cmdb_handler()

app = Flask(__name__)

@app.route("/")
def index():
    return "hello world"
  
  
@app.route("/get")
def get():
    """查询CMDB"""
    ret = CMDB_HANDLER.execute("get", path)
    return ret
  
  
@app.route("/init", methods=["POST"])
def init():
    """初始化地域"""
    ret = CMDB_HANDLER.execute("get", region)
    return ret

  
@app.route("/add", methods=["POST"])
def add():
    """添加信息"""
    ret = CMDB_HANDLER.execute("get", path, attr)
    return ret
  
  
@app.route("/update", methods=["POST"])
def update():
    """修改信息"""
    ret = CMDB_HANDLER.execute("get", path, attr)
    return ret
  

@app.route("/delete", methods=["POST"])
def delete():
    """删除信息"""
    ret = CMDB_HANDLER.execute("get", path, attr)
    return ret
  
if __name__ == "__main__":
    app.run(debug=True)

上述代码有一个需要注意的地方就是@app.route("/init", methods=["POST"]),路由装饰器可以传入另外一个参数methods,这个参数会对HTTP请求的方式做出限制,methods=["POST"]表示该URL只接收POST请求,该参数不传时默认允许GET方法。

默认浏览器中输入网址访问属于对该URL发起GET请求,如果发起请求的方式与后端路由允许接收的方式不匹配,会发生如下图现象

在这里插入图片描述

Tips

此处需要说明,不同框架对于请求方法的限制处理方式不同。

Flask中只要请求的URL与路由定义的名称相同即可匹配成功,匹配成功后Flask会再对请求的Method做校验,判断请求方式与路由允许的接收方式是否一致,如果不一致则直接返回Method Not Allowed。

但在其他框架中,如Golang的Web框架,是将路由的名称和允许接收的请求方式组合后同时去和收到的HTTP请求做对比,如果不匹配就会报出404 Not Found错误。

也就是说 Flask是通过名称来唯一定义一个路由,而其他框架则是用名称和Method来唯一定义一个路由。

四、接收参数

细心的朋友可能发现,上述代码中调用CMDB的功能时,需要传入一些参数,但Flask应用中并没有定义这些参数

1.GET请求参数

CMDB查询功能的代码如下:

@app.route("/get")
def get():
    """查询CMDB"""
    ret = CMDB_HANDLER.execute("get", path)
    return ret

由于我们是HTTP请求方式,所以上述代码中的path参数需要从HTTP请求中获取,这里是GET请求,通常GET请求的传参方式为

http://ip:port/path?key1=value1&key2=value2

HTTP请求的参数会经过Flask框架的处理,将参数存放在request.args中,request.args是一个字典,所以代码可以修改如下:

from flask import Flask, request

@app.route("/get")
def get():
    """查询CMDB"""
    path = request.args.get("path", "/")  # 如果没有传path参数,则path默认为 / 
    ret = CMDB_HANDLER.execute("get", path)
    return ret
2.POST请求参数

在CMDB中新增数据的代码如下:

@app.route("/add", methods=["POST"])
def add():
    """添加信息"""
    ret = CMDB_HANDLER.execute("get", path, attr)
    return ret

从上述代码可以看出,这个路由只允许接收POST请求。其实目前对于GET请求,或者必须要用POST请求,并没有明确的区分,或者准确 的说就是没有区分,任何功能都可以通过GET请求来实现,这个我们会在番外篇中详细讲解。

但由于在CMDB中添加信息时,需要传入的内容是json字符串,放在GET请求的参数中存在转义问题和可读性问题,所以我们这里采用POST请求来处理。

POST请求可以接受的参数可以有很多中类型,类型由HTTP请求Headers中的content-type字段定义,常用的有application/json或者application/x-www-form-urlencoded,我们这里暂且采用后者,代码修改如下:

from flask import Flask, request

@app.route("/add")
def add():
    """添加信息"""
    path = request.form.get("path")
    attr = request.form.get("attr")
    ret = CMDB_HANDLER.execute("add", path, attr)
    return ret

【总结】

这一章节主要介绍了以下几个内容:

1.Flask的启动

2.路由函数的定义

3.HTTP参数的获取

4.Web应用与CMDB的结合

这些都还只是Flask的冰山一角,我们下一章节会针对这次的代码做出更进一步的改进,敬请期待。

【篇后语】

大家可以看到,我们只应用了Flask的及其有限的知识,并且没有应用到特别复杂的项目架构,部分知识也没有十分深入的探索,实际上就可以完成很多需求,这就是我开头提到的最小化上手范围;这也十分符合编程的理念:不要过度设计,不要提早重构

Flask目前有很多官方的文档,也有许多讲解十分全面的书籍。我个人也十分赞同可以系统的去学习某个技术,但平时知乎上经常有人提问我看了很多书为什么还是不会写代码,诸如此类的问题,其实这也是大多数编程经验较少的朋友都会遇到的一个问题:懂得太多

懂得太多

这里的“懂”和“多”都是加引号的,因为如果真的懂,那必然是一个好事情,同样如果真的懂得多,也是个好事情。

但问题在于部分朋友对于很多知识点并不是真的懂,同样也就造成了多的错觉,因为确实也看了不少,这就涉及到了我之前在【自动化运维新手村】Python与面向对象-3的篇后语中提到的:指令学习和归纳学习,没看过的朋友可以点链接去看看。

阅读书籍或文档中的知识讲解本质上属于指令学习,学到的是知识点,但学习编程是一种归纳学习,需要将学会的知识点不停的运用,去反复并且多角度的验证这个知识点是具有实操性的,最终才能叫做“学会它”。

所以有的朋友看完书之后就会有一种感觉,这么多知识点我都知道了,但还是不会写代码,工作中遇到需求还是无法下手,根本原因就是知识点在脑子中堆积太多,但无法消化;更为通俗的讲就是步子迈得太大了。

所以为了避免从入门到放弃,希望大家切记慢既是快


欢迎大家添加我的个人公众号【Python玩转自动化运维】加入读者交流群,获取更多干货内容