Python中Flask框架的使用详解

首页 » Python » Python中Flask框架的使用详解

Flask是一个轻量级的基于Python的web框架。在学习之前,你可能需要有一点HTML、Python、的基础,如果没有,呢也可以通过敲代码而记住也是可以的…本文在Windows环境下,pycharm中Python3.7进行测试。

Flask的安装

一般在国内使用pycharm进行安装需要的库的时候,建议直接在pycharm的Terminal终端输入命令进行安装,具体命令可参考:

pip install --default-timeout=5000 Flask
 

安装一般都会成功,一次不行,再试一次,总有成功的一次。好了,接着我们可以显示一些基本的关于Flask的一些信息,代码参考:

import flask
print(flask.__doc__)#引入Flask,然后打印一些东西:Flask的介绍和版本:
 

Hello World

万物皆可Hello World,那么首先我们可以使用Flask,显示一个Hello World的Web程序,代码参考:

from flask import Flask
app=Flask(__name__)
@app.route('/')
def hello_word():
    return 'Hello World!'
if __name__=='__main__':
    app.run()
 

运行之后,你会在控制台看到一些信息,那么你首先看到的可能就是一个网址,那么不用好奇立马打开这个网址,就会在一个网页看到Hello World,在pycharm的控制台会显示你的每一次点击。

修改Flask的配置

app = Flask(__name__)
 

python内置变量__name__的值是字符串__main__ 。Flask类将这个参数作为程序名称。当然这个是可以自定义的,比如app = Flask(“my-app”)。这个可以随意设置,这只是运行后显示的名字,但是不能空值。

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

app = Flask("my-app", static_folder="path1", template_folder="path2")
 

更多参数请参考__doc__:

from flask import Flask
    print(Flask.__doc__)
 

或者你可以在Flask上,按住Ctrl+鼠标单击,就会进入Flask的源代码,那么写的是非常清楚,自己浏览一下即可。

Flask的调试模式

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

app.run(debug=True)
 

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

绑定IP和端口

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

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

0.0.0.0代表电脑所有的IP。80是HTTP网站服务的默认端口。

获取 URL 参数

URL参数是出现在url中的键值对,例如http://127.0.0.1:5000/?disp=3中的url参数是{‘disp’:3}。

列出所有的url参数

from flask import Flask,request
app=Flask(__name__)
@app.route('/')
def hello_world():
    return request.args.__str__()
if __name__=='__main__':
    app.run(debug=True)
 

然后我们在浏览器中访问http://127.0.0.1:5000/?name=e1yu.com&page=1&type=utf8&code=我爱你么么,其实在控制台中输出的并不是这个url地址,我们可以在后面加上一些参数,这里就是随便加,需要注意的是每个参数之间&分割,http://127.0.0.1:5000/后面需要?来添加参数。

ImmutableMultiDict([('name', 'e1yu.com'), ('page', '1'), ('type', 'utf8'), ('code', '我爱你么么')])
 

那么浏览器传给我们的Flask服务的数据长什么样子呢?可以通过request.full_path和request.path来看一下:

from flask import Flask,request
app=Flask(__name__)
@app.route('/')
def hello_world():
    print(request.path)#返回请求的路径
    print(request.full_path)#返回请求的参数
    return request.args.__str__()
if __name__=='__main__':
    app.run(debug=True)
 

运行我们还是访问一些带参数的url,可以接着访问上面带参数的url,然后就会在控制台看到一些信息,只可自己尝试,不在显示具体内容。

获取某个指定的参数

要获取键code对应的值,可以修改一下代码:

from flask import Flask,request
app=Flask(__name__)
@app.route('/')
def hello_world():
    print(request.path)#返回请求的路径
    print(request.full_path)#返回请求的参数
    return request.args.get('code')
if __name__=='__main__':
    app.run(debug=True)
 

再次访问http://127.0.0.1:5000/?name=e1yu.com&page=1&type=utf8&code=%E6%88%91%E7%88%B1%E4%BD%A0%E4%B9%88%E4%B9%88,就只会显示code的参数,可以看到,我这个url是从浏览器的搜索框中直接复制的,中文直接转换为符合url格式,其实就是’我爱你么么’

那么我们去访问控制台中的url地址,其实也就是不带参数的url:http://127.0.0.1:5000/,就会报错,相关报错信息不再展示。这是因为没有在URL参数中找到code。所以request.args.get(‘code’)返回Python内置的None,而Flask不允许返回None。解决方法很简单,我们先判断下它是不是None:

from flask import Flask,request
app=Flask(__name__)
@app.route('/')
def hello_world():
    res=request.args.get('code')
    if res==None:
        return '404错误,换个姿势搜索'
    return res
if __name__=='__main__':
    app.run(debug=True)
 

之后运行,再次访问:http://127.0.0.1:5000/,就不会报错了。还有一种request.args.get接收默认值:

res = request.args.get('code', '404错误,换个姿势重试一次')
 

url参数存在多个相同值

还有一种情况就是,如果我们的url参数中出现多个相同的参数时,request.args.get只能获取第一个参数,这时候就可以使用request.args.getlist(‘参数’) ,该方法返回的是一个list,比较简单,这里自行尝试。

获取POST方法传送的数据

作为一种HTTP请求方法,POST用于向指定的资源提交要被处理的数据。我们在某网站注册用户、写文章等时候,需要将数据传递到网站服务器中。并不适合将数据放到URL参数中,密码放到URL参数中容易被看到,文章数据又太多,浏览器不一定支持太长长度的URL。这时,一般使用POST方法。

#server服务器端
from flask import Flask,request
app=Flask(__name__)
@app.route('/')
def hello_world():
    return ''
@app.route('/reg',methods=['POST'])
def reg():
    print(request.headers)#打印请求头信息
    print(request.stream.read())#打印请求的具体信息
    return 'Hello World!\nThis is a POST request'
if __name__=='__main__':
    app.run(debug=True)
 

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

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

那么启动上面的代码之后我们就可以使用Python的爬虫去请求这个网址http://127.0.0.1:5000/reg,其实就是一个服务端,一个客户端,跟我们爬虫请求别的网站是一样的,但是如果你直接在浏览器中输入这个网址,那么显示的就是:

Method Not Allowed

The method is not allowed for the requested URL.
 

这大概是由于浏览器使用的是Get请求,而我们创建的代码中是没有Get请求的,所以我们使用Python爬虫的Post请求网址:

#client客户端
import requests
user_info={'name':'e1yu.com','password':123}
res=requests.post('http://127.0.0.1:5000/reg',data=user_info)
print(res.text)
 

那么运行之后会在两个终端输出不同的信息。前6行是client.py生成的HTTP请求头,由print(request.headers)输出。请求体的数据,我们通过print(request.stream.read())输出,结果是:

b'name=e1yu.com&password=123'
 

解析POST数据

我们可以看到POST请求的具体信息了,那么我们想要把name、password提取出来,Flask内置了解析器request.form。
我们将服务器端代码改成:

from flask import Flask,request
app=Flask(__name__)
@app.route('/')
def hello_world():
    return ''
@app.route('/reg',methods=['POST'])
def reg():
    print(request.headers)
  # print(request.stream.read()) # 不要用,否则下面的form取不到数据
    print(request.form)
    print(request.form['name'])
    print(request.form.get('name'))
    print(request.form.getlist('name'))
    print(request.form.get('names',default='little name'))
    return 'Hello World!\nThis is a POST request'
if __name__=='__main__':
    app.run(debug=True)
 

request.form会自动解析数据。request.form[‘name’]和request.form.get(‘name’)都可以获取name对应的值。对于request.form.get()可以为参数default指定值以作为默认值。所以会返回:

ImmutableMultiDict([('name', 'e1yu.com'), ('password', '123')])
e1yu.com
e1yu.com
['e1yu.com']
little name
 

如果name有多个值,可以使用request.form.getlist(‘name’),该方法将返回一个列表。这可以自行修改Python爬虫的参数,重新请求即可,我们可以根据下标来取出想要的值,因为它是一个list列表。

处理和响应JSON数据

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

处理JSON格式的请求数据

如果POST的数据是JSON格式,request.json会自动将json数据转换成Python类型(字典或者列表)。那么需要修改服务器端:

from flask import Flask,request
app=Flask(__name__)
@app.route('/')
def hello_world():
    return ''
@app.route('/reg',methods=['POST'])
def reg():
    print(request.headers)
    print(type(request.json))
    print(request.json)
    result=request.json['a']+request.json['b']
    return str(result)
if __name__=='__main__':
    app.run(debug=True)
 

Python爬虫的请求端,可以把数据更换为json格式,代码参考:

import requests
json_info={'a':1,'b':2,'c':3}
res=requests.post('http://127.0.0.1:5000/reg',json=json_info)
print(res.text)
 

运行的结果自己尝试,需要注意的是,请求头中Content-Type的值是application/json,那么我们的服务器端,就需要返回给我们爬虫一些信息,用什么格式请求的,就应当返回什么格式的响应。

响应JSON-方案1

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

from flask import Flask,request,Response
import json
app=Flask(__name__)

@app.route('/reg',methods=['POST'])
def reg():

    result={'sum':request.json['a']+request.json['b']}
    return Response(json.dumps(result),mimetype='application/json')
if __name__=='__main__':
    app.run(host='127.0.0.1',port=5000,debug=True)
 

对应的Python爬虫请求端,也需要做一些修改:

import requests
json_info={'a':1,'b':2,'c':3}
res=requests.post('http://127.0.0.1:5000/reg',json=json_info)
print(res.headers)
print(res.text)

#{'Content-Type': 'application/json', 'Content-Length': '10', 'Server': 'Werkzeug/1.0.0 Python/3.7.3', 'Date': 'Sat, 07 Mar 2020 02:33:37 GMT'}
#{"sum": 3}
 

上面第一段内容是服务器的响应头,第二段内容是响应体,也就是服务器返回的JSON格式数据。但是,我们通常在使用爬虫请求某个网址的时候,它的服务器返回的数据可不像我们的这么简单。我们需要让这个服务器的HTTP响应头具有更好的可定制性,比如自定义Server,可以如下修改reg()函数:

@app.route('/reg',methods=['POST'])
def reg():
    result={'sum':request.json['a']+request.json['b']}
    res=Response(json.dumps(result),mimetype='application/json')
    res.headers.add('Server','python flask')
    return res
 

响应JSON-方案2

在flask中我们可以使用自带的 jsonify 函数即可。具体代码参考:

from flask import Flask,request,jsonify
app=Flask(__name__)

@app.route('/reg',methods=['POST'])
def reg():
    result=request.json['a']+request.json['b']

    return jsonify(result)
if __name__=='__main__':
    app.run(host='127.0.0.1',port=5000,debug=True)
 

Python爬虫请求端,也就是我们的客户端不用做任何修改,返回的都是差不多的。

文件的上传

上传文件,一般也是用POST方法。我们以上传图片为例:假设将上传的图片只允许’png’、’jpg’、’jpeg’、’gif’这四种格式,通过url/upload使用POST上传,上传的图片存放在服务器端的static/uploads目录下。

from flask import Flask,request
import os
from werkzeug.utils import secure_filename
app=Flask(__name__)

#支持的文件格式
app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif'}  # 集合类型
#判断文件名是否是我们支持的格式
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.',1)[1] in app.config['ALLOWED_EXTENSIONS']
@app.route('/upload',methods=['POST'])
def upload():
    upload_file=request.files['image']
    if upload_file and allowed_file(upload_file.filename):
        filename=secure_filename(upload_file.filename)
        
        upload_file.save(os.path.join(app.root_path,filename))
        return 'info is'+request.form.get('info','')+'. success'
    else:
        return 'failed'

if __name__=='__main__':
    app.run(port=5000,debug=True)
 

app.config中的config是字典的子类,可以用来设置自有的配置信息,也可以设置自己的配置信息。函数allowed_file(filename)用来判断filename是否有后缀以及后缀是否在app.config[‘ALLOWED_EXTENSIONS’]中。upload_file是上传文件对应的对象。app.root_path获取server.py所在目录在文件系统中的绝对路径。upload_file.save(path)用来将upload_file保存在服务器的文件系统中,参数最好是绝对路径,否则会报错(网上很多代码都是使用相对路径,但是笔者在使用相对路径时总是报错,说找不到路径)。函数os.path.join()用来将使用合适的路径分隔符将路径组合起来。

import requests
file_data={'image':open('1.jpg','rb')}
user_info={'info':'e1yu'}
res=requests.post('http://127.0.0.1:5000/upload',data=user_info,files=file_data)
print(res.text)
 

要控制上产文件的大小,可以设置请求实体的大小,例如:

app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 #16MB
 

不过,在处理上传文件时候,需要使用try:…except:…。

如果要获取上传文件的内容可以:

file_content = request.files['image'].stream.read()
 

Restful URL

简单来说,Restful URL可以看做是对 URL 参数的替代。

from flask import Flask
app=Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'
@app.route('/user/<username>')
def user(username):
    print(username)
    print(type(username))
    return 'Hello '+username
@app.route('/user/<username>/friends')
def user_friends(username):
    print(username)
    print(type(username))
    return 'Hello '+username
if __name__=='__main__':
    app.run(debug=True)

 

使用浏览器访问http://127.0.0.1:5000/user/e1yu,在控制台将输出:

 e1yu
<class 'str'>
 

而访问http://127.0.0.1:5000/user/e1yu/,响应为404 Not Found。浏览器访问http://127.0.0.1:5000/user/e1yu/friends,可以看到:Hello e1yu。在控制台将会输出:

e1yu
<class 'str'>
 

转换类型

由上面的示例可以看出,使用 Restful URL 得到的变量默认为str对象。如果我们需要通过分页显示查询结果,那么需要在url中有数字来指定页数。按照上面方法,可以在获取str类型页数变量后,将其转换为int类型。不过,还有更方便的方法,就是用flask内置的转换机制,即在route中指定该如何转换。

from flask import Flask
app=Flask(__name__)
@app.route('/')
def hello_world():
    return 'Hello World!'
@app.route('/page/<int:num>')
def page(num):
    print(num)
    print(type(num))
    return 'Hello World!'
if __name__=='__main__':
    app.run(debug=True)
 

@app.route(‘/page/‘)会将num变量自动转换成int类型。运行上面的程序,在浏览器中访问http://127.0.0.1:5000/page/123,控制台将输出如下内容:

123
<class 'int'>
 

但是访问http://127.0.0.1:5000/page/abc,我们会得到404响应。在官方资料中,说是有3个默认的转换器:

 int     accepts integers
    float     like int but for floating point values
    path     like the default but also accepts slashes
 

编写转换器

自定义的转换器是一个继承werkzeug.routing.BaseConverter的类,修改to_python和to_url方法即可。to_python方法用于将url中的变量转换后供被`@app.route包装的函数使用,to_url方法用于flask.url_for`中的参数转换。

浏览器访问http://127.0.0.1:5000/page/123后,HelloWorld/server.py的输出信息是:

使用redirect重定向网址

redirect函数用于重定向,实现机制很简单,就是向客户端(浏览器)发送一个重定向的HTTP报文,浏览器会去访问报文中指定的url。

from flask import Flask, url_for, redirect
 
app = Flask(__name__)
 
@app.route('/')
def hello_world():
    return 'hello world'
 
@app.route('/test1')
def test1():
    print('this is test1')
    return redirect(url_for('test2'))
 
@app.route('/test2')
def test2():
    print('this is test2')
    return 'this is test2'
 
if __name__ == '__main__':
    app.run(debug=True)
 

在浏览器中访问http://127.0.0.1:5000/test1,浏览器的url会变成http://127.0.0.1:5000/test2,并显示:this is test2

自定义404等错误的响应

要处理HTTP错误,可以使用flask.abort函数。

from flask import Flask, render_template_string, abort
 
app = Flask(__name__)
 
 
@app.route('/')
def hello_world():
    return 'hello world'
 
 
@app.route('/user')
def user():
    abort(401)  # Unauthorized 未授权
    print('Unauthorized, 请先登录')
 
 
if __name__ == '__main__':
    app.run(port=5000, debug=True)
 

要注意的是,代码中abort(401)后的print并没有执行。或者可以采用下面的这种方式自定义错误页面:

from flask import Flask, render_template_string, abort
 
app = Flask(__name__)
 
 
@app.route('/')
def hello_world():
    return 'hello world'
 
 
@app.route('/user')
def user():
    abort(401)  # Unauthorized
 
 
@app.errorhandler(401)
def page_unauthorized(error):
    return render_template_string('<h1> Unauthorized </h1><h2>{{ error_info }}</h2>', error_info=error), 401
 
 
if __name__ == '__main__':
    app.run(port=5000, debug=True)
 

page_unauthorized函数返回的是一个元组,401 代表HTTP 响应状态码。如果省略401,则响应状态码会变成默认的 200。

用户会话

session用来记录用户的登录状态,一般基于cookie实现。

未经允许不得转载:作者:鳄鱼君, 转载或复制请以 超链接形式 并注明出处 鳄鱼君
原文地址:《Python中Flask框架的使用详解》 发布于2020-03-06

分享到:
赞(0) 赏杯咖啡

评论 抢沙发

4 + 2 =


文章对你有帮助可赏作者一杯咖啡

支付宝扫一扫打赏

微信扫一扫打赏

Vieu4.6主题
专业打造轻量级个人企业风格博客主题!专注于前端开发,全站响应式布局自适应模板。
切换注册

登录

忘记密码 ?

您也可以使用第三方帐号快捷登录

Q Q 登 录
微 博 登 录
切换登录

注册