python flask框架详解
python flask框架详解
Flask是一个python编写的web微框架,让我们可以使用python语言快速实现一个网站或Web服务。
1.安装flask
pip install flask
2.简单上手
一个最小的Flask应用如下:
from flask import Flask
app=Flask(__name__)@app.route('/')
def hello_world():return 'Hello Word'if __name__=='__main__':app.run()
代码解释:
1.首先我们导入了Flask类。该类的实例将会成为我们的WSGI应用。
2.接着我们创建一个该类的实例。第一个参数是应用模块或者包的名称。如果你使用一个单一模块(就像本例),那么应当使用name,因为名称会根据这个模块是按应用方式使用还是作为一个模块导入而发生变化(可能是’main’,也可能是实际导入的名称)。这个参数是必须的,这样Flask才能知道在哪里可以找到模板和静态文件等东西
3.然后我们使用route()装饰器来告诉Flask触发函数的URL
4.函数名称被用于生成相关联的URL。函数最后返回需要在用户浏览器中显示的信息。
app.route(rule,options)
- rule参数表示与该函数的URL绑定。
- option是要转发给基础Rule对象的参数列表。
在上面的示例中,‘/’ URL与hello_world()函数绑定。因此,当在浏览器中打开web服务器的主页时,将呈现该函数的输出。
最后,Flask类的run()方法在本地开发服务器上运行应用程序。
app.run(host,port,debug,options)
所有参数都是可选的
- host:要监听的主机名。默认为127.0.0.1(localhost)。设置为’0.0.0.0‘以使服务器在外部可用
- port:默认值为500
- debug:默认为false。如果设置为true,则提供调试信息,可以自动重载代码并显示调试信息
- options:要转发到底层的Werkzeug服务器
2.1调试模型
虽然flask命令可以方便地启动一个本地开发服务器,但是每次应用代码修改之后都需要手动重启服务器。这样不是很方便,Flask可以做得更好。如果你打开调试模式,那么服务器会在修改应用代码之后自动重启,并且当应用出错时还会提供一个有用的调式器。
在命令行中,如果需要打开所有开发功能(包括调试模式),那么要在运行服务器之前导出FLASK_ENV环境变量并把其设置为development.
$ export FLASK_ENV=development
$ flask run
在代码中,在运行或将调试参数传递给run()方法之前,通过将application对象的debug属性设置为True来启动Debug模式。
app.debug=True
app.run()
# 或者
app.run(debug=True)
2.2绑定IP和端口
默认情况下,Flask绑定IP为127.0.0.1,端口为500.我们可以通过下面的方式自定义:
app.run(host='0.0.0.0',port=80,debug=True)
0.0.0.0代表电脑所有的IP。80是HTTP网站服务的默认端口。什么是默认?比如,我们访问网站http://www.example.com,其实是访问的http://www.example.com:80,只不过:80可以省略不写。
3.Flask路由
现代Web框架使用路由技术来帮助用户记住应用程序URL。可以直接访问所需的页面,而无需从主页导航。
Flask中的route()装饰器用于将URL绑定到函数。例如:
@qpp.route('/hello')
def hello_world():return 'hello world'
在这里,URL '/hello’规则绑定到hello_world()函数。因此,如果用户访问http://localhost:5000/hello URL,hello_world()函数的输出将在浏览器中呈现。
application对象的add_url_rule()函数也可用于将URL与函数绑定,如上例所示,使用route()装饰器的目的也由以下表示:
def hello_world():return 'hello world'
app.add_url_rule('/','hello',hello_world)
4.Flask变量规则
通过向规则参数添加变量部分,可以动态构建URL。此变量部分标记为converter:variable_name 。它作为关键字参数传递给与规则相关联的函数。
在以下示例中,route()装饰器的规则参数包括附加到URL '/hello’的.因此,如果在浏览器中输入http://localhost:5000/hello/lzz作为URL,则‘lzz’将作为参数提供给hello()函数。
from flask import Flask
app=Flask(__name__)@app.route('./hello/<name>')
def hello_name(name):return f'Hello {name}'
if __name__=='__main__':app.run(debug=True)
运行,访问:http://localhost:5000/hello/lzz
除了默认字符串变量部分之外,还可以使用以下转换器构建规则:
转换器 | 描述 |
---|---|
string | (缺省值)接受任何不包括斜杠的文本 |
int | 接受正整数 |
float | 接受正浮点数 |
path | 类似string,但可以包含斜杠 |
uuid | 接受UUID字符串 |
from flask import Flask
app=Flask(__name__)@app.route('/post/<int:post_id>')
def show_post(post_id):return f'Post {post_id}'@app.route('./path/<path:subpath>')
def show_subpath(subpath):return f'Subpath {subpath}'
if __name__=='__main__':app.run(debug=True)
4.1唯一的URL/重定向行为
以下两条规则的不同之处在于是否使用尾部的斜杆。
@app.route('/projects/')
def projects():return 'The project paage'
@app.route('/about')
def about():return 'The about page'
projects的URL是中规中矩的,尾部有一个斜杠,看起来就如同一个文件夹。访问一个没有斜杆结尾的URL时Flask会自动进行重定向,帮你在尾部加上一个斜杆。
about的URL没有尾部斜杆,因此其行为表现与一个文件类似。如果访问这个URL时添加了尾部斜杆就会得到一个404错误。这样可以保持URL唯一,并帮助搜索引擎避免重复索引同一页面。
5.Flask URL构建
url_for()函数对于动态构建特定函数的URL非常有用。该函数接受函数的名称作为第一个参数,以及一个或多个关键字参数,每个参数对应于URL的变量部分。
from flask import Flask,redirect,url_forapp=Flask(__name__)@app.route('./admin')
def hello_admin():return 'Hello Admin'@app.route('./guest/<guest>')
def hello_guest(guest):return f'Hello {guest} as Guest'@app.route('./user/<name>')
def hello_user(name):if name=='admin':return redirect(url_for('hello_admin'))else:return redirect(url_for('hello_guest',guest=name))if __name__=='__main__':app.run(debug=True)
redirect函数用于重定向,实现机制很简单,就是向客户端(浏览器)发送一个重定向的HTTP报文,浏览器会去访问报文中指定的url.
运行,打开浏览器并输入http://localhost:5000/user/admin和http://localhost:5000/user/mvl
6.Flask HTTP方法
Web应用使用不同的HTTP方法处理URL。当你使用Flask时,应当熟悉HTTP方法。缺省情况下,一个路由只回应GET请求。可以使用route()装饰器的methods参数来处理不同的HTTP方法:
方法 | 描述 |
---|---|
GET | 以未加密的形式将数据发送到服务器,最常见的方法。 |
HEAD | 和GET方法相同,但没有响应体 |
POST | 用于将HTML表单数据发送到服务器,POST方法将接收的数据不由服务器缓存 |
PUT | 用上传的内容替换目标资源的所有当前表示 |
DELETE | 删除由URL给出的目标资源的所有当前表示 |
默认情况下,Flask路由相应GET请求。但是,可以通过为route()装饰器提供方法参数来更改此首选项。
为了演示在URL路由中使用POST方法,首先让我们创建一个HTML表单,并使用POST方法将表单数据发送到URL。
将以下脚本另存为login.html
<html><body><form action='http://locallhost:5000/login' method='post'><p>Enter Name:</p><p> <input type="text" name="nm"></p><p> <input type="submit" value="submit"></p></form></body>
</html>
from flask import Flask,url_for,redirect,request
app=Flask(__name__)@app.route('/success/<name>')
def success(name):return f'welcom{name}'@app.route('/login',methods=['POST','GET'])
def login():if request.method=='POST':user=request.form['nm']return redirect(url_for('success',name=user))else:user=request.args.get('nm')return redirect(url_for('success',name=user))
if __name__=='__main__':app.run(debug=True)
在浏览器中打开login.html,在文本字段中输入name,然后单击提交。
表单数据将POST到表单标签的action子句中的URL。
http://localhost/login映射到login()函数。由于服务器通过POST方法接收数据,因此通过以下步骤获得从表单数据获得的’nm’参数的值:
表单数据将POST到表单标签的action子句中的URL。
user=request.form['nm']
它作为变量部分传递给’/success’URL.浏览器在窗口中显示welcome消息。
在login.html中将方法参数更改为’GET‘,然后再浏览器中再次打开它。服务器上接收的数据是通过GET方法获得的。通过一些的步骤获得’nm’参数的值:
User=request.args.get('nm')
这里,args是包含表单参数对及其对应值对的列表的字典对象。与‘nm’参数对应的值将像之前一样传递到’/success’URL.
7.Flask模板
在大型应用中,把业务逻辑和表现内容放在一起,会增加代码的复杂度和维护成本
- 模板其实就是一个包含响应文本的文件,其中用占位符(变量)表示动态部分,告诉模板引擎其具体的值需要从使用的数据中获取
- 使用真实值替换变量,再返回最终得到的字符串,这个过程称为“渲染”
- Flask是使用Jinja2这个模板引擎来渲染模板
使用模板的好处
- 视图函数只负责业务逻辑和数据处理(业务逻辑方面)
- 而模板则取到视图函数的数据结果进行展示(视图展示方面)
- 代码结构清晰,耦合度低
使用render_template()方法可以渲染模板,你只要提供模板名称和需要作为参数传递给模板的变量就行了。
Flask会在templates文件夹内寻找模板。因此,如果你的应用是一个模块,那么模板文件夹应该在模板旁边;如果是一个包,那么就应该在包里面:
情形1:一个模块:
/application.py
/templates/hello.html
情形2:一个包:
/application/__init__.py/templates/hello.html
示例代码:
from flask import Flask,render_template
app=Flask(__name__)@app.route('/')
def index():my_int=18my_str='curry'my_list=[1,5,4,3,2]my_dict={'name':'durant','age':28}# render_template方法:渲染模板# 参数1:模板名称 参数n:传到模板里的数据return render_template('hello.html',my_int=my_int,my_str=my_str,my_list=my_list,my_dict=my_dict)
if __name__=='__main__':app.run(debug=True)
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><title>Title</title>
</head>
<body><h2>我是模板</h2>{{my_int}}<br>{{my_str}}<br>{{my_list}}<hr><h2>模板的list数据获取</h2><hr>{{my_list[0]}}<br>{{my_list.1}}<hr><h2>字典数据获取</h2><hr>{{my_dict['name']}}<br>{{my_dict.age}}<h2>算术运算</h2><br>{{my_list.0+10}}<br>{{my_list[0]+my_list.1}}
</body>
</html>
8.Flask静态文件
动态的web应用也需要静态文件,一般是CSS和JavaScript文件。理想情况下你的服务器已经配置好了为你的提供静态文件的服务。但是在开发过程中,Flask也能做好这项工作。只要在你的包或模块旁边创建一个名为static的文件夹就行了。静态文件位于应用的/static中。
使用特定的‘static’端点就可以生成相应的URL
url_for('static',filename='style.css')
这个静态文件在文件系统中的位置应该是static/style.css
在下面的示例中,在index.html中的HTML按钮的OnClick事件上调用hello.js定义的javascript函数,该函数在Flask应用程序的’/‘URL上呈现。
from flask import Flask,render_template
app=Flask(__name__)@app.route('/')
def index():return render_template('index.html')
if __name__=='__main__':app.run(debug=True)
index.html的HTML脚本如下所示:
<html><head><script type="text/javascript" src="{{url_for('static',filename='hello.js')}}"></script></head><body><input type="button" onclick="sayHello()"></body>
</html>
Hello.js包含Hello()函数
function sayHello(){alert('hello world')
}
9.Flask Request对象
来自客户端网页的数据作为全局请求对象发送到服务器。为了处理请求数据,应该从Flask模块导入。
Request对象的重要属性如下所列:
- form-它是一个字典对象,包含表单参数及其值得键和值对
- args-解析查询字符串得内容,它是问号(?)之后得URL得一部分。
- Cookies-保存Cookie名称和值得字典对象。
- files-与上传文件有关得数据。
- method-当前请求方法
首先,你必须从flask模块导入请求对象:
from flask import request
9.1Flask将表单数据发送到模板
我们已经看到,可以在URL规则中指定http方法。触发函数接收得Form数据可以以字典对象得形式收集它并将其转发到模板以在相应得网页上呈现它。
在以下示例中,‘/‘URL会呈现具有表单的网页(student.html).填入的数据会发布到触发result()函数的’/result’ URL.
result()函数收集字典对象中的request.form中存在的表单数据,并将其发送给result.html。
该模板动态呈现表单数据的HTML表格。
下面给出的是应用程序的Python代码:
from flask import Flask,render_template,request
app=Flask(__name__)
@app.route('/')
def student():return render_template('student.html')@app.route('/result',methods=['POST','GET'])
def result():if request.method=='POST':result=request.formreturn render_template('result.html',result=result)
if __name__=='__main__':app.run(debug=True)
下面给出student.html的HTML脚本
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="http://localhost:5000/result" method="POST"><p>Name <input type="text" name="Name"></p><p>Physics <input type="text" name="Physics"></p><p>Chemistry <input type="text" name="Chemistry"></p><p>Maths <input type="text" name="Maths"></p><p><input type="submit" name="submit"></p></form></body>
</html>
下面给出模板(result.html)的代码:
<table border=1>
{% for key ,value in result.items() %}<tr><th>{{key}}</th><td>{{value}}</tr>{% endfor %}
</table>
9.2Flask Cookies
Cookie以文本文件的形式存储在客户端的计算机上。其目的是记住和跟踪与客户使用相关的数据,以获得更好的访问者体验和网站统计信息。
Request对象包含Cookie的属性。它是所有cookie变量及其对应值的字典对象,客户端已传输。除此之外,cookie还存储其网站的到期时间,路径和域名。
在Flask中,对cookie的处理步骤为:
1.设置cookies:
设置cookie,默认有效期是临时cookie,浏览器关闭就失效可以通过max_age设置有效期,单位是秒
resp=make_response('success')#设置响应体
resp.set_cookie('lzz','play basketball',max_age=3600)
2.获取cookie
获取cookie,通过request.cookies的方式,返回的是一个字典,可以获取字典里的相应的值。
cookie_1=request.cookies.get('lzz')
3.删除cookie
这里的删除只是让cookie过期,并不是直接删除cookie
删除cookie,通过delete_cookie()的方式,里面的cookie的名字
resp=make_response('del success') # 设置响应体
resp.delete_cookie('lzz')
以下为Flask Cookies的简单示例:
from flask import Flask ,make_response,request
app=Flask(__name__)@app.route('/set_cookies')
def set_cookie():resp=make_response('success')resp.set_cookie('lzz','play basketball',max_age=3600)return resp
@app.route('/get_cookies')
def get_cookie():cookie_1=request.cookies.get('lzz')return cookie_1@app.route('/delete_cookies')
def delete_cookie():resp=make_response('del success')resp.delete_cookie('lzz')return resp
if __name__=='__main__':app.run(debug=True)
设置cookies
运行127.0.0.1:5000/set_cookies
获取cookie 运行 http://127.0.0.1:5000/get_cookies
删除cookie 运行 http://127.0.0.1:5000/delete_cookies
10.Flask 会话
与Cookie不同,Session(会话)数据存储在服务器上。会话是客户端登录到服务器并注销服务器的时间间隔。需要在该会话中保存的数据会存储在服务器上的临时目录中。
为每个客户端的会话分配会话ID。会话数据存储在coolie的顶部,服务器以加密方式对其进行签名。对于此加密,Flask应用程序需要一个定义的SECRET_KEY.
Session对象也是一个字典对象,包含会话变量和关联值得键值对。
例如,要设置一个’username‘会话变量,请使用以下语句:
Seesion['username']='admin'
要释放会话变量,请使用pop()方法。
session.pop('username',None)
演示代码:
from flask import Flask, session, redirect, url_for, requestapp = Flask(__name__)app.secret_key = 'fkdjsafjdkfdlkjfadskjfadskljdsfklj' # 确保设置应用程序的secret_key@app.route('/')
def index():if 'username' in session:username = session['username']return '登录用户名是:' + username + '<br>' + \"<b><a href = '/logout'>点击这里注销</a></b>"return "您暂未登录, <br><a href = '/login'></b>" + \"点击这里登录</b></a>"@app.route('/login', methods=['GET', 'POST'])
def login():if request.method == 'POST':session['username'] = request.form['username']return redirect(url_for('index'))return '''<form action = "" method = "post"><p><input type ="text" name ="username"/></p><p><input type ="submit" value ="登录"/></p></form>'''@app.route('/logout')
def logout():# remove the username from the session if it is theresession.pop('username', None)return redirect(url_for('index'))if __name__ == '__main__':app.run(debug=True)
如何生成一个好得密钥:
生成随机数得关键在于一个好的随机种子,因此一个好的密钥应当有足够的随机性。操作系统可以有多种方式基于密码随机生成器来生成随机数据。使用下面的命令可以快捷的为Flask.secret_key(或者SECRET_KEY)生成值:
$ python -c ‘import os; print(os.urandom(16))’
b’_5#y2L"F4Q8z\n\xec]/’
11.Flask重定向和错误
Flask类有一个redirect()函数。调用时,它返回一个响应对象,并将用户重定向到具有指定状态代码的另一个目标位置。
redirect()函数的原型如下:
Flask.redirect(location,statuscode,response)
在上述函数中:
- location参数是应该重定向响应的URL
- statuscode发送到浏览器标头,默认为302
- response参数用于实例化响应
以下状态码已标准化:
- HTTP_300_MULTIPLE_CHOICES
HTTP_301_MOVED_PERMANENTLY
HTTP_302_FOUND
HTTP_303_SEE_OTHER
HTTP_304_NOT_MODIFIED
HTTP_305_USE_PROXY
HTTP_306_RESERVED
HTTP_307_TEMPORARY_REDIRECT
默认状态码为302,表示’found’
在以下示例中,redirect()函数用于在登录尝试失败时再次显示登录页面。
from flask import Flask ,redirect,url_for,render_template,request
app=Flask(__name__)@app.route('/')
def index():return render_template('login.html')
@app.route('/login',methods=['POST','GET'])
def login():if request.method=='POST' and request.form['username']=='admin':return redirect(url_for('success'))return redirect(url_for('index'))
@app.route('/success')
def success():return 'logged in successfully'
if __name__=='__main__':app.run(debug=True)
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title>
</head>
<body><form action="http://localhost:5000/login" method="POST"><p>Enter name:</p><p><input type="text" name="username"></p><p><input type="submit" value="submit"></p></form></body>
</html>
Flask类具有带有错误代码 的abort()函数。
Flask.abort(code)
Code参数采用以下值之一:
- 400 - 用于错误请求
- 401 - 用于未身份验证的
- 403 - Forbidden
- 404 - 未找到
- 406 - 表示不接受
- 415 - 用于不支持的媒体类型
- 429 - 请求过多
让我们对上述代码中的login()函数稍作更改。如果显示‘Unauthurized’页面,请将其替换为调用abort(401),而不是显示登录页面。
from flask import Flask ,redirect,url_for,render_template,request
app=Flask(__name__)@app.route('/')
def index():return render_template('login.html')@app.route('/login',methods=['POST','GET'])
def login():if request.method=='POST':if request.form['username']=='admin':return redirect(url_for('success'))else:abort(401)else:return redirect(url_for('index'))@app.route('/success')
def success():return 'logged in successfully'if __name__=='__main__':app.run(debug=True)
运行,输入非admin的用户名,点击提交
12.Flask消息闪现
一个好的基于GUI的应用程序会向用户提供有关交互的反馈。例如,桌面应用程序使用对话框或消息框,JavaScript使用警报用于类似目的。
在Flask Web应用程序中生成这样的信息性消息很容易。Flask框架的闪现系统可以在一个视图中创建消息,并在名为next的视图函数中呈现它。
Flask模块包含flash()方法。它将消息传递给下一个请求,该请求通常是一个模板。
flash(message,caategory)
其中,
- message参数要闪现的实际消息。
- category参数是可选的。它可以是”error",“info"或“warning”.
为了从会话中获取消息,模板调用get_flashed_messaegs().
以下是一个完整的示例:
from flask import Flask,flash,redirect,render_template,request,url_forapp=Flask(__name__)
app.secret_key=b'_5#y2L"F4Q8z\n\xec]/'@app.route('/')
def index():return render_template('index.html')@app.route('/login',methods=['POST','GET'])
def login():error=Noneif request.method=='POST':if request.form['username']!='admin' or request.form['password']!='secret':error='Invalid credentials'else:flash('You were successfully logged in')return redirect(url_for('index'))return render_template('login.html',error=error)
if __name__=='__main__':app.run(debug=True)
以下是实现闪现的layout.html模板:
{% with messages = get_flashed_messages() %}{% if messages %}<ul class=flashes>{% for message in messages %}<li>{{ message }}</li>{% endfor %}</ul>{% endif %}
{% endwith %}
{% block body %}{% endblock %}
以下是继承自layout.html的index.html模板:
{% block body %}<h1>Overview</h1><p>Do you want to <a href="{{ url_for('login')}}">login?</a></p>{% endblock %}
以下是同样继承自layout.html的login.html模板:
{% extends "layout.html" %}
{% block body %}<h1>Login</h1>{% if error %}<p class="error"><strong>Error:</strong>{{ error}}</P>{% endif %}<form method="post"><dl><dt>Username:</dt><dd><input type="text" name=username value="{{request.form.username}}"></dd><dt>Password:</dt><dd><input type="password" name="password"></dd></dl><p><input type="submit" value="Login"></p></form>
{% endblock %}
13.Flask文件上传
在Flask中处理文件上传非常简单。它需要一个HTML表单,其enctype属性设置为’multipart/form-data’,将文件发布到URL。URL处理程序从request.files[]对象中提取文件,并将其保存到所需的位置。
每个上传的文件首先会保存在服务器上的临时位置,然后将其实际保存到它的最终位置。目标文件的名称可以是硬编码的,也可以从request.files[file]对象的filename属性中获取。但是,建议使用secure_filename()函数获取它的安全版本。
可以在Flask对象的配置设置中定义默认上传文件夹的路径和上传文件的最大大小。
app.config[‘UPLOAD_FOLDER’]定义上传文件夹的路径
app.config[‘MAX_CONTENT_LENGTH’]指定要上传的文件的最大大小(以字节为单位)
以下代码具有’/upload’ URL规则,该规则在templates文件夹中显示’upload.html’,以及’/upload-file’URL规则,用于调用uploader()函数处理上传过程。
’upload.html’有一个文件选择器按钮和一个提交按钮。
<html>
<head><title>File Upload</title>
</head>
<body><form action="http://localhost:5000/uploader" method="post" enctype="multipart/form-data"><input type="file" name="file" accept=".jpg,.png"><input type="submit"> </form>
</body>
</html>
以下是Flask应用程序的Python代码
from flask import Flask,render_template,request
from werkzeug.utils import secure_filename
import osapp=Flask(__name__)
app.config['UPLOAD_FOLDER']='D:\Data'@app.route('/upload')
def upload_file():return render_template('upload.html')@app.route('/uploader',methods=["GET",'POST'])
def uploader():if request.method=='POST':f=request.form['file']f.save(os.path.join(app.config['UPLOAD_FOLDER'],secure_filename(f.filename)))return 'file uploaded successfully'
if __name__=='__main__':app.run()
选择文件夹后,单击提交。表单的post方法调用’/upload_file’URL.底层函数uploader()执行保存操作。