• Flask新手教程


    Flask简介

    Flask是一个轻量级的可定制框架,使用Python语言编写,较其他同类型框架更为灵活、轻便、安全且容易上手。

    Flask 可以很好地结合MVC模式进行开发,开发人员分工合作,小型团队在短时间内就可以完成功能丰富的中小型网站或Web服务的实现。

    Flask还有很强的定制性,用户可以根据自己的需求来添加相应的功能,在保持核心功能简单的同时实现功能的丰富与扩展,其强大的插件库可以让用户实现个性化的网站定制,开发出功能强大的网站。

    Flask主要特征

    Flask是目前十分流行的web框架。

    Flask 被称为微框架(microframework),“微”并不是意味着把整个Web应用放入到一个Python文件,微框架中的“微”是指Flask旨在保持代码简洁且易于扩展。

    Flask框架的主要特征是核心构成比较简单,但具有很强的扩展性和兼容性,程序员可以使用Python语言快速实现一个网站或Web服务

    Flask两个核心函数库

    Flask主要包括Werkzeug和Jinja2两个核心函数库,它们分别负责业务处理和安全方面的功能,这些基础函数为web项目开发过程提供了丰富的基础组件。

    Werkzeug

    Werkzeug库十分强大,功能比较完善,支持URL路由请求集成,一次可以响应多个用户的访问请求;

    支持Cookie和会话管理,通过身份缓存数据建立长久连接关系,并提高用户访问速度;支持交互式Javascript调试,提高用户体验;

    可以处理HTTP基本事务,快速响应客户端推送过来的访问请求。

    Jinja2

    Jinja2库支持自动HTML转移功能,能够很好控制外部黑客的脚本攻击。系统运行速度很快,页面加载过程会将源码进行编译形成python字节码,从而实现模板的高效运行;

    模板继承机制可以对模板内容进行修改和维护,为不同需求的用户提供相应的模板。

    Flask 基本模式

    Flask的基本模式是在程序里将一个视图函数分配给一个URL,每当用户访问这个URL时,系统就会执行给该URL分配好的视图函数,获取函数的返回值并将其显示到浏览器上,工作过程见图。

    Flask 安装

     安装

    通过pip安装Flask即可:

    pip install Flask

    如果你的命令是pip3, 则使用 pip3 install Flask 

    进入python交互模式看下Flask的介绍:

    我们可以看到Flask使用 BSD 授权。

    查看一下flask版本:

    我们使用的Flask版本号是 1.1.1

    Flask 目录结构

    我们通过别人的目录大致了解一下flask框架的目录结构。

    1. flask-demo/
    2. ├ run.py # 应用启动程序
    3. ├ config.py # 环境配置
    4. ├ requirements.txt # 列出应用程序依赖的所有Python包
    5. ├ tests/ # 测试代码包
    6. │ ├ __init__.py
    7. │ └ test_*.py # 测试用例
    8. └ myapp/
    9. ├ admin/ # 蓝图目录
    10. static/
    11. │ ├ css/ # css文件目录
    12. │ ├ img/ # 图片文件目录
    13. │ └ js/ # js文件目录
    14. ├ templates/ # 模板文件目录
    15. ├ __init__.py
    16. ├ forms.py # 存放所有表单,如果多,将其变为一个包
    17. ├ models.py # 存放所有数据模型,如果多,将其变为一个包
    18. └ views.py # 存放所有视图函数,如果多,将其变为一个包

    当然我们不需要创建这么多文件和文件夹也能运行Flask, 下面的课程会介绍到。

    Hello World 开始

    本节主要内容:使用Flask写一个显示 "Hello World!"的web程序,如何配置、调试Flask。

    创建项目

    我们手动创建文件夹和文件结构如下:

    1. py/
    2. static/ # static用来存放静态资源,例如图片、js、css文件等
    3. ├ templates/ # templates存放模板文件
    4. ├ server.py

    我们的网站逻辑基本在server.py文件中,当然,也可以给这个文件起个其他的名字。

    server.py中加入以下内容:

    1. from flask import Flask
    2. app = Flask(__name__)
    3. @app.route('/')
    4. def hello_world():
    5. return 'Hello World!'
    6. if __name__ == '__main__':
    7.     app.run()

     运行server.py

    1. python3 server.py
    2. * Running on http://127.0.0.1:5000/

    打开浏览器访问http://127.0.0.1:5000/

    代码解析

    变量app是一个Flask实例,通过下面的方式:

    1. @app.route('/')
    2. def hello_world():
    3. return 'Hello World!'

    当客户端访问/时,将响应hello_world()函数返回的内容。注意,这不是返回Hello World!这么简单,Hello World!只是HTTP响应报文的实体部分,状态码等信息既可以由Flask自动处理,当然也可以通过编程来制定。

    修改Flask的配置

    app = Flask(__name__)

    上面的代码中,python内置变量__name__的值是字符串__main__ 。Flask类将这个参数作为程序名称。当然这个是可以自定义的,比如:

    app = Flask("myapp")

    Flask默认使用static目录存放静态资源,templates目录存放模板,也可以通过设置参数更改:

    app = Flask("myapp", static_folder="path1", template_folder="path2")

    以上我们指定静态资源目录为path1, 模板目录为 path2。

    更多参数请参考__doc__

    1. from flask import Flask
    2. print(Flask.__doc__)

    调试模式

    上面的server.py中以app.run()方式运行,这种方式下,如果服务器端出现错误是不会在客户端显示的。但是在开发环境中,显示错误信息是很有必要的,要显示错误信息,应该以下面的方式运行Flask:

    app.run(debug=True)

    debug设置为True的另一个好处是,程序启动后,会自动检测源码是否发生变化,若有变化则自动重启程序。这可以帮我们省下很多时间。

    还可以使用这种途径开启调试模式:

    1. app.debug = True
    2. app.run()

    绑定IP和端口

    默认情况下,Flask绑定IP为127.0.0.1,端口为5000。也可以通过下面的方式自定义:

    app.run(host='0.0.0.0', port=8080, debug=True)

    0.0.0.0代表电脑所有的IP。以上我们绑定了8080端口, 启动服务后我们访问的网址将是: http://127.0.0.1:8080/

    列出所有的url参数

    在server.py中添加以下内容:

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/')
    4. def hello_world():
    5. return request.args.__str__()
    6. if __name__ == '__main__':
    7. app.run(port=5000, debug=True)

    在浏览器中访问http://127.0.0.1:5000/?name=Loen&age&app=ios&app=android,将显示:

    ImmutableMultiDict([('name', 'Loen'), ('age', ''), ('app', 'ios'), ('app', 'android')])

    中文

    较新的浏览器也支持直接在url中输入中文(最新的火狐浏览器内部会帮忙将中文转换成符合URL规范的数据),在浏览器中访问http://127.0.0.1:5000/?info=我爱你,将显示:

    ImmutableMultiDict([('info', '我爱你')])

    request.full_path和request.path

    可以通过request.full_pathrequest.path 查看浏览器传给我们的Flask服务的数据

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/')
    4. def hello_world():
    5. print(request.path) # 这里的 print 会在控制台中输出
    6. print(request.full_path)
    7. return request.args.__str__()
    8. if __name__ == '__main__':
    9. app.run(port=5000, debug=True)

    浏览器访问http://127.0.0.1:5000/?info=我爱你&to=girl,运行server.py的终端会输出:

     获取指定的参数值

    例如,要获取键info对应的值,如下修改server.py

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/')
    4. def hello_world():
    5. return request.args.get('info')
    6. if __name__ == '__main__':
    7. app.run(port=5000)

    运行server.py,在浏览器中访问http://127.0.0.1:5000/?info=我爱你&to=girl,浏览器将显示:

    开启debug

    不过,当我们访问http://127.0.0.1:5000/时候却出现了500错误,浏览器显示:

    我们返回server.py, 开启debug

    再次访问:

    这是因为Flask不允许返回None, 而没有在URL参数中找到info。所以request.args.get('info') 返回Python内置的None。

    解决方法很简单,我们先判断下它是不是None:

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/')
    4. def hello_world():
    5. r = request.args.get('info')
    6. if r==None:
    7. # do something
    8. return ''
    9. return r
    10. if __name__ == '__main__':
    11. app.run(port=5000, debug=True)

    也可以, 设置默认值,也就是取不到数据时用这个值:

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/')
    4. def hello_world():
    5. r = request.args.get('info', 'welcome')
    6. return r
    7. if __name__ == '__main__':
    8. app.run(port=5000, debug=True)

    函数request.args.get的第二个参数用来设置默认值。此时在浏览器访问http://127.0.0.1:5000/,将显示:

    welcome

    getlist 如何处理多值

    如果我们请求 http://127.0.0.1:5000/?name=Loen&age&app=ios&app=android,仔细看下,app有两个值。

    如果我们的代码是:

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/')
    4. def hello_world():
    5. r = request.args.get('app')
    6. return r
    7. if __name__ == '__main__':
    8. app.run(port=5000, debug=True)

    在浏览器中请求时,我们只会看到 ios

    我们可以使用getlist获取所有的app的值

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/')
    4. def hello_world():
    5. r = request.args.getlist('app') # 返回一个list
    6. return str(r)
    7. if __name__ == '__main__':
    8. app.run(port=5000, debug=True)

    浏览器输入 http://127.0.0.1:5000/?name=Loen&age&app=ios&app=android,我们会看到['ios', 'android']

    获取POST方法传送的数据

    作为一种HTTP请求方法,POST用于向指定的资源提交要被处理的数据。

    比如: 我们在某网站注册用户、写文章等时候,需要将数据传递到网站服务器中。并不适合将数据放到URL参数中,密码放到URL参数中容易被看到,文章数据又太多,浏览器不一定支持太长长度的URL。这时,一般使用POST方法。

    本课程使用python的requests库模拟浏览器。

    安装方法:

    pip install requests

    看POST数据内容

    以用户注册为例子,我们需要向服务器/register传送用户名name和密码password。如下编写server.py。

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/register', methods=['POST'])
    4. def register():
    5. print(request.headers)
    6. print(request.stream.read())
    7. return 'welcome'
    8. if __name__ == '__main__':
    9. app.run(port=5000, debug=True)

    @app.route('/register', methods=['POST'])​是指url​/register​只接受POST方法。可以根据需要修改methods参数,例如如果想要让它同时支持GET和POST,这样写:

    @app.route('/register', methods=['GET', 'POST']) 

    浏览器模拟工具client.py内容如下:

    1. import requests
    2. user_info = {'name': 'Loen', 'password': 'loveyou'}
    3. r = requests.post("http://127.0.0.1:5000/register", data=user_info)
    4. print(r.text)

    运行server.py,然后运行client.pyclient.py将输出:

    welcome

    而server.py在终端中输出以下调试信息(通过print输出):

    前6行是client.py生成的HTTP请求头,由print(request.headers)输出。

    请求体的数据,我们通过print(request.stream.read())输出,结果是:

    b'name=Loen&password=loveyou'

    解析POST数据

    上面,我们看到post的数据内容是:

    b'name=Loen&password=loveyou'
    

    我们要想办法把我们要的name、password提取出来,怎么做呢?

    Flask已经内置了解析器request.form。

    我们将服务代码改成:

    1. from flask import Flask, request
    2. app = Flask(__name__)
    3. @app.route('/register', methods=['POST'])
    4. def register():
    5. print(request.headers)
    6. # print(request.stream.read()) # 不要用,否则下面的form取不到数据
    7. print(request.form)
    8. print(request.form['name'])
    9. print(request.form.get('name'))
    10. print(request.form.getlist('name'))
    11. print(request.form.get('nickname', default='little apple'))
    12. return 'welcome'
    13. if __name__ == '__main__':
    14. app.run(port=5000, debug=True)

    执行client.py请求数据,服务器代码会在终端输出:

    request.form会自动解析数据。

    request.form['name']和request.form.get('name')都可以获取name对应的值。对于request.form.get()可以为参数default指定值以作为默认值。所以:

    print(request.form.get('nickname', default='little apple'))

    输出的是默认值

    little apple

    获取POST中的列表数据

    如果name有多个值,可以使用request.form.getlist('name'),该方法将返回一个列表。我们将client.py改一下:

    1. import requests
    2. user_info = {'name': ['Loen', 'Alan'], 'password': 'loveyou'}
    3. r = requests.post("http://127.0.0.1:5000/register", data=user_info)
    4. print(r.text)

    此时运行client.pyprint(request.form.getlist('name'))将输出:

    [u'Loen', u'Alan']

    处理和响应JSON数据

    使用 HTTP POST 方法传到网站服务器的数据格式可以有很多种,比如「获取POST方法传送的数据」课程中讲到的name=Loen&password=loveyou这种用过&符号分割的key-value键值对格式。我们也可以用JSON格式、XML格式。相比XML的重量、规范繁琐,JSON显得非常小巧和易用。

    如果POST的数据是JSON格式,request.json会自动将json数据转换成Python类型(字典或者列表)。

    编写server.py:

    1. from flask import Flask, request
    2. app = Flask("myapp")
    3. @app.route('/add', methods=['POST'])
    4. def add():
    5. print(request.headers)
    6. print(type(request.json))
    7. print(request.json)
    8. result = request.json['n1'] + request.json['n2']
    9. return str(result)
    10. if __name__ == '__main__':
    11. app.run(host='127.0.0.1', port=5000, debug=True)

    编写client.py模拟浏览器请求:

    1. import requests
    2. json_data = {'n1': 5, 'n2': 3}
    3. r = requests.post("http://127.0.0.1:5000/add", json=json_data)
    4. print(r.text)

    运行server.py,然后运行client.pyclient.py 会在终端输出:

    注意,请求头中Content-Type的值是application/json

    响应JSON

    响应JSON时,除了要把响应体改成JSON格式,响应头的Content-Type也要设置为application/json。

    编写server.py:

    1. from flask import Flask, request, Response
    2. import json
    3. app = Flask("myapp")
    4. @app.route('/add', methods=['POST'])
    5. def add():
    6. result = {'sum': request.json['n1'] + request.json['n2']}
    7. return Response(json.dumps(result), mimetype='application/json')
    8. if __name__ == '__main__':
    9. app.run(host='127.0.0.1', port=5000, debug=True)

    修改后运行。

    编写client.py:

    1. import requests
    2. json_data = {'n1': 5, 'n2': 3}
    3. r = requests.post("http://127.0.0.1:5000/add", json=json_data)
    4. print(r.headers)
    5. print(r.text)

    运行client.py,将显示:

    client终端返回的第一段内容是服务器的响应头,第二段内容是响应体,也就是服务器返回的JSON格式数据。

    另外,如果需要服务器的HTTP响应头具有更好的可定制性,比如自定义Server,可以如下修改add()函数:

    1. @app.route('/add', methods=['POST'])
    2. def add():
    3. result = {'sum': request.json['n1'] + request.json['n2']}
    4. resp = Response(json.dumps(result), mimetype='application/json')
    5. resp.headers.add('Server', 'python flask')
    6. return resp

    client.py运行后会输出:

    1. {'Content-Type': 'application/json', 'Content-Length': '10', 'Server': 'python flask', 'Date': 'Wed, 11
    2. Sep 2019 09:09:18 GMT'}
    3. {"sum": 8}

    响应JSON

    使用 jsonify 工具函数。

    1. from flask import Flask, request, jsonify
    2. app = Flask("myapp")
    3. @app.route('/add', methods=['POST'])
    4. def add():
    5. result = {'sum': request.json['n1'] + request.json['n2']}
    6. return jsonify(result)
    7. if __name__ == '__main__':
    8. app.run(host='127.0.0.1', port=5000, debug=True)

    运行结果:

     

     

  • 相关阅读:
    RocketMQ如何实现消息的顺序性
    sqlite 判断数据表是否存在 失效的一种情况
    金仓数据库KingbaseES客户端编程接口指南-Nodejs(4. 示例)
    我的y9000p-i9-12900h购买之旅
    Ubuntu 支持小米四足机器人“铁蛋”;GitHub 首席运营官离职;JetBrains 为 Kotlin 推出跨平台 UI 框架 | 开源日报
    百度资深架构师谈:为什么Java开发工程师工资高,却很多人想转行
    LeetCode 0123.买卖股票的最佳时机III:常数空间下的动态规划+模拟
    Elasticsearch:ES|QL 查询语言简介
    Thread 类的基本用法
    C++、C++-OpenCV、Python、Python-Numpy、MATLAB的除法取余方法总结
  • 原文地址:https://blog.csdn.net/m0_61981943/article/details/131391922