操作系统: Window 10
工具:Pycharm
Python: 3.7
使用 python 的框架,一般最好是弄一个虚拟环境,在虚拟环境内使用框架,这样比较方便后面的项目封装打包,而且可以对该项目运行环境与其他的项目的运行环境进行一个隔离,不会导致版本的冲突。
具体的看创建虚拟环境实操链接
cd 虚拟环境下的 Scripts 目录下
这样才可以调用虚拟环境内的 pip 指令下载 Flask 框架,而不是给本地下载 Flask 框架
pip install flask
最好在虚拟环境目录的Scripts目录下,安装Flask框架模块。
Flask 项目最好是手动创建虚拟环境,然后在Pycharm开发工具内创建Flask 项目,具体如下所示:
上面红框内虚拟环境名\config
是在虚拟环境内新建的项目文件夹 config
,Flask
项目的脚本文件都放在这里,下面的红框内的解释器路径是之前创建好的虚拟环境的python解释器的路径,注意这里指定好了(FlaskProject),而不是(FlaskProject)(1) 或 (FlaskProject)(2)、(FlaskProject)(3)…(FlaskProject)(n),这里就是 Pycharm 神奇的地方了,重复创建一个虚拟环境下的python解释器,让人感觉很难受,所以才强调要用手动创建虚拟环境。
当然为什么坚持要使用虚拟环境,这是为了运行环境隔离,后期封装就简单多了。
对于 Flask
框架来说,一个 python
文件就是一个 app
最小应用代码演示:
# app.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
保存为一个 app.py
脚本文件,当然需要注意的是以后给文件起名字,请确保你不会将它的文件名弄成 flask.py
,这样会和 Flask 框架文件名冲突的。
运行 python
命令:(前面我弄了一个 FlaskProject 的 virtualenv
虚拟环境,后面就一直用这个虚拟环境,学习 Flask 框架)
这里分为两种运行方式:一种是Pycharm,另外一种是Windows 终端,不过这里就混合使用两种方式来测试,可以对比一下。
Pycharm运行
直接点击蓝色的URL,就可以自动弹出网页
Windows终端运行
终端运行成功,后在浏览器输入 127.0.0.1:5000 就可以看到结果 Hello World!
不过,看到红色的没有,警告 Warning
,其实也没啥,只是 WSGI 没开启,这个模式用于开发环境调试,部署线上需要使用WSGI替代,所以这里就需要启动 WSGI 服务。
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
警告:这是一个开发服务器。不要在生产部署中使用它。使用一个生产WSGI服务器代替。
解决方法:
参考链接:
https://blog.csdn.net/panruola/article/details/106012487
https://blog.csdn.net/GodDavide/article/details/103712131
https://www.cnblogs.com/mlp1234/p/13743254.html
http://www.wsmee.com/post/79
其实初学者,不建议一开始就按照我下面的做法,下面环节只是后期要做的,只是大致给个具体的做法而已。一般还是先用上面环节内的 app.run,正式环节才采用下面的开启 wsgi 服务器的做法。
安装 gevent
模块,导入 pywsgi
,代码如下所示:
# hello.py
from flask import Flask
from gevent import pywsgi
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
server = pywsgi.WSGIServer(('0.0.0.0', 5000), app)
server.serve_forever()
0.0.0.0
—— 这会让操作系统监听所有公网 IP。
结果如下:
这里就不会弹出类似这种的输出显示了
而是这种,好像没运行一样的空白终端。
不过得在终端ipconfig
一下,找到自己 ip 地址,如果有多个 ip 地址,也没问题,反正只要是自己电脑所属的 ip 地址就行,就可以访问本机电脑服务器,然后随便输入自己电脑的 ip 地址 和 端口号,就可以了。这里可以弄一个测试用的静态 ip 地址,进行测试。
终端会显示有如下的访问记录
虽然
run()
方法适用于启动本地的开发服务器,但是 你每次修改代码后都要手动重启它。这样并不够优雅,而且Flask
可以做到更 好。如果你启用了调试支持,服务器会在代码修改后自动重新载入,并在发生 错误时提供一个相当有用的调试器。
有两种途径来启用调试模式。一种是直接在应用对象上设置:
# hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.debug = True
app.run()
另一种是作为 run 方法的一个参数传入:
# hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run(debug=True)
两种方法的效果完全相同。
debug
- 是否开启调试模式并捕获异常
注意
尽管交互式调试器在允许fork
的环境中无法正常使用(即在生产服务器上正常使用几乎是不可能的),但它依然允许执行任意代码。这使它成为一 个巨大的安全隐患,因此它 绝对不能用于生产环境 。
参考链接:
https://www.w3cschool.cn/flask_1/flask_1-74fv3ixu.html
app.run
个人理解:
app.run
提供一个调试模式供开发者去自行开发项目,这个run
方法,一般是用于开发环节使用的,而不是生产上线环节,而且由于有安全隐患,就更不能用于生产环境,此外,可以开启其调试模式,方便项目开发调试。
URL
(Uniform Resource Locator
,统一资源定位器)能够用人所熟悉易于记忆的方式,来指向某个网站网页或文件,而不是用 ip
地址,这样的数字化思维去记忆,这是其很方便且极其重要的特点,我是这样理解的。
Flask 框架对于 URL
是一种绑定的思路,具体实现方法是利用一个 route()
的装饰器来绑定特定的 URL
与 指定的函数 / 方法,实现的代码如下:
# hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello_world():
return 'Hello World!'
if __name__ == '__main__':
app.run()
@
符号后加app.route()
等同于调用装饰器,来装饰下面某个def
方法, 括号内指定某个URL
字符串 ,下一行则是指定某个URL
特定函数 / 方法
突然想来对比下两个框架的路由,没学过 Django 框架的,可以翻过了。
Django
框架的路由实现思路是 主路由表、子路由表及路由URL
绑定;
Flask
框架的路由实现思路是 路由URL
绑定;
这么一想,其实都是有共同点的,那就是路由 URL
绑定,都是通过路由 URL
绑定一个实现 URL
回传 html
的方法,只不过 Django
框架有着主路由表和子路由表,Flask
框架没有,仅仅是 路由 URL
绑定,有点像是精简了路由的 Django
框架。
Flask
框架的 URL
内是可以传递变量的,该变量包括了传递用户名、表单的 id
号等等,而且这些变量是可以指定数据类型的,如整型、浮点型以及路径字符串。
要给
URL
添加变量部分,你可以把这些特殊的字段标记为,
这个部分将会作为命名参数传递到你的函数。规则可以用\
指定一个可选的数据类型转换器。这里有一些不错的例子:
@app.route('/user/' )
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
@app.route('/post/' )
def show_post(post_id):
# show the post with the given id, the id is an integer
return 'Post %d' % post_id
转换器有下面几种:
类型 | 作用 |
---|---|
int |
接受整数 |
float |
同 int ,但是接受浮点数 |
path |
和默认的相似,但也接受斜线 |
Flask
的URL
规则基于Werkzeug
的路由模块。这个模块背后的思想是基 于Apache
以及更早的HTTP
服务器主张的先例,保证优雅且唯一的URL
。
首先,先向大家介绍一下什么是
Werkzeug
,Werkzeug
是一个WSGI
工具包,他可以作为一个Web框架的底层库。这里稍微说一下,Werkzeug
不是一个web服务器,也不是一个web框架,而是一个工具包,官方的介绍说是一个 WSGI 工具包,它可以作为一个 Web框架的底层库,因为它封装好了很多 Web 框架的东西,例如Request
,Response
等等。
其中Flask
框架就是以Werkzeug
为基础开发的
以这两个 URL
规则为例:
# hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/test1/')
def urltest1():
return '有斜线'
@app.route('/test2')
def urltest2():
return '没有斜线'
if __name__ == '__main__':
app.run(debug = True)
测试 1:
输入URL
:127.0.0.1:5000/test1/
测试 2:
输入 URL
:127.0.0.1:5000/test1
测试 3:
输入 URL
:127.0.0.1:5000/test2
测试 4:
输入 URL
:127.0.0.1:5000/test2/
参考引用:
第一种情况中,指向 projects 的规范
URL
尾端有一个斜线。这种感觉 很像在文件系统中的文件夹。访问一个结尾不带斜线的URL
会被 Flask 重定向到带斜线的规范URL
去。
然而,第二种情况的URL
结尾不带斜线,类似 UNIX-like 系统下的文件的 路径名。访问结尾带斜线的URL
会产生一个404 “Not Found”
错误。 这个行为使得在遗忘尾斜线时,允许关联的URL
接任工作,与Apache
和其它的服务器的行为并无二异。此外,也保证了URL
的唯一,有助于 避免搜索引擎索引同一个页面两次。
Flask
框架的路由 URL
绑定方法,一开始的路由 URL
绑定是否添加斜杠的区别是很大的,加斜杠了访问的是文件夹,不加斜杠的访问的是文件 —— 文件夹可以攘括了所有的文件,文件单单指的是某种类型的一个文件,文件夹可以补全斜杠,而文件无法补全斜杠。
404
报错,也是因为找不到文件夹,定义为文件,那么自然不会有文件夹。
用
url_for()
来给指定的函数构造URL
。它接受函数名作为第一个 参数,也接受对应URL
规则的变量部分的命名参数。未知变量部分会添加到URL
末尾作为查询参数。
代码例子演示:
# app.py
from flask import Flask, url_for
app = Flask(__name__)
@app.route('/') # 客户端请求的URL
def index():
pass
@app.route('/login') # 客户端请求的URL
def login():
pass
@app.route('/user/' ) # 客户端请求的URL
def profile(username):
pass
with app.test_request_context(): # 服务端回传的URL
print(url_for('index')) # 服务端回传的URL
print(url_for('login')) # 服务端回传的URL
print(url_for('login', test='/')) # 服务端回传的URL
print(url_for('profile', username='John Doe')) # 服务端回传的URL
login
是无参数方法且作为 url_for()
的第一个参数,第二个参数,指的是URL
,而 ? 后的未知变量部分,而且等于号 = 后为字符串形式’ ’ / " "
特别注意:URL是斜杠
/
,而Windows的文件路径是反斜杠\
profile
是有参数方法,因为有参数,可以作为关键字参数传参,所以不像 login
那样,有一个 test 这样的 ?
未知变量部分,直接传递参数数值,无需添加 ?
未知变量部分
为什么你要构建
URL
而非在模板中硬编码?这里有三个绝妙的理由:
- 反向构建通常比硬编码的描述性更好。更重要的是,它允许你一次性修改
URL
, 而不是到处边找边改。URL
构建会转义特殊字符和Unicode
数据,免去你很多麻烦。- 如果你的应用不位于
URL
的根路径(比如,在 /myapplication 下,而不 是/
),url_for()
会妥善处理这个问题。
url_for()
这里是生成 URL
是一种灵活的方法,url_for()
绑定的是方法,返回值是route()
装饰器的 URL
参数加上变量部分,从而生成的 URL
结果。这里要特别注意的一点是,方法,也就是函数,在绑定 URL
路由时,路由的名字,也就是斜杠 /
后的 URL
部分,是否要和方法同名,这一点得灵活一点,可以一样,我认为有时为了安全,需要不一样,如下所示:
浏览器的发送数据请求方法,是有好几种的不同的方法的,最常见的是 GET
和 POST
—— GET
请求的内容是显示在 URL
这里,而 POST
请求请求的内容是放在请求的包内的,比较安全。
Flask 框架的
HTTP
(与 Web 应用会话的协议)有许多不同的访问URL
方法。默认情况下,路 由只回应GET
请求,但是通过route()
装饰器传递methods
参数可以改变这个行为。
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
do_the_login()
else:
show_the_login_form()
如果存在
GET
,那么也会替你自动地添加HEAD
,无需干预。它会确保 遵照< a rel="nofollow" class="reference external" href="http://www.ietf.org/rfc/rfc2068.txt" rel="external nofollow" target="_blank" >HTTP RFC
(描述 HTTP 协议的文档)处理HEAD
请求,所以你可以 完全忽略这部分的HTTP
规范。同样,自从Flask 0.6
起, 也实现了OPTIONS
的自动处理。
这里只是大致介绍 HTTP
的常用一些方法,详情请自行搜索相关内容。
HTTP 方法(也经常被叫做“谓词” —— 动词 请求…)告知服务器,客户端想对请求的页面 做 些什么。自从
Flask 0.6
起, 也实现了OPTIONS
的自动处理。 下面的都是非常常见的方法:
GET
浏览器告知服务器:只获取页面上的信息并发给我。这是最常用的方法。
HEAD
浏览器告诉服务器:欲获取信息,但是只关心 消息头 。应用应像处理
GET
请求一样来处理它,但是不分发实际内容。在Flask
中你完全无需人工干预,底层的Werkzeug
库已经替你打点好了。
POST
浏览器告诉服务器:想在
URL
上 发布 新信息。并且服务器必须确保 数据已存储且仅存储一次。这是HTML
表单通常发送数据到服务器的方法。
PUT
类似
POST
但是服务器可能触发了存储过程多次,多次覆盖掉旧值。你可能会问这有什么用,当然这是有原因的。考虑到传输中连接可能会丢失,在这种情况下浏览器和服务器之间的系统可能安全地第二次接收请求,而不破坏其它东西。因为POST
它只触发一次,所以用POST
是不可能的。可靠性问题,上传大文件,可以使用PUT
。
DELETE
删除给定位置的信息。
OPTIONS
给客户端提供一个敏捷的途径来弄清这个
URL
支持哪些HTTP
方法。 从Flask 0.6
开始,实现了自动处理。
简洁记忆:
也就是说 methods
的参数值是一个 list
列表,列表 list
里面的请求方法,都是一个字符串类型的数据。
有趣的是,在
HTML4
和XHTML1
中,表单只能以GET
和POST
方法提交到 服务器。但是JavaScript
和未来的HTML
标准(如HTML 5
)允许你使用其它所有的方法。此 外,HTTP
最近变得相当流行,浏览器不再是唯一的HTTP
客户端。比如,许多版本控制系统就在使用HTTP
。
动态 web 应用也会需要静态文件,通常是
CSS
和JavaScript
文件。理想状况下, 你已经配置好 Web服务器来提供静态文件,但是在开发中,Flask
也可以做到。 只要在你的包中或是模块的所在目录中创建一个名为static
的文件夹,在应用中使用/static
即可访问。
给静态文件生成 URL
,使用特殊的 'static'
端点名:
url_for('static', filename='style.css')
这个文件应该存储在文件系统上的 static/style.css
。
Flask
的静态文件默认是在 /static/
的目录,在这个目录下,比如一些静态、动态图片、还有一些例如javascript
文件或支持网页显示的CSS
文件等等,都可以放在这里面,而首页这些html
模板文件,就都放在 templates
目录下,并且使用方法 render_templates(html文件)
,Flask
框架会在这个目录下查找html模板文件。
代码演示:
# app.py
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)
\templates\index.html
文件内容:
<html>
<head>
<script type = "text/javascript"
src = "{{ url_for('static', filename = 'hello.js') }}" >script>
head>
<body>
<input type = "button" onclick = "sayHello()" value = "Say Hello" />
body>
html>
\static\hello.js
文件内容:
function sayHello() {
alert("Hello World")
}
来自客户端网页的数据作为全局请求对象发送到服务器。为了处理请求数据,应该从Flask模块导入。
Request对象的重要属性如下所列:
参数 | 功能 |
---|---|
Form |
它是一个字典对象,包含表单参数及其值的键和值对。 |
args |
解析查询字符串的内容,它是问号(?)之后的URL 的一部分。 |
Cookies |
保存Cookie 名称和值的字典对象。 |
files |
与上传文件有关的数据。 |
method |
当前请求方法 |
python代码文件:
# app.py
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.form
return render_template("result.html",result = result)
if __name__ == '__main__':
app.run(debug = True)
student.html
表单模板文件:
<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 = "Mathematics" />p>
<p><input type = "submit" value = "submit" />p>
form>
表单处理结果回传result.html
模板文件
doctype html>
<table border = 1>
{% for key, value in result.items() %}
<tr>
<th> {{ key }} th>
<td> {{ value }}td>
tr>
{% endfor %}
table>
Cookie以文本文件的形式存储在客户端的计算机上。其目的是记住和跟踪与客户使用相关的数据,以获得更好的访问者体验和网站统计信息。
Request对象包含Cookie的属性。它是所有cookie变量及其对应值的字典对象,客户端已传输。除此之外,cookie还存储其网站的到期时间,路径和域名。
这说明Cookie能够设置登录连接时长和是否启用关闭浏览器等于关闭登录连接。
- 设置客户端的cookie:
设置cookie,默认有效期是临时cookie,浏览器关闭就失效
可以通过max_age
设置有效期, 单位是秒
set_cookie(cookie="",value="",max_age=None,expires=None,path="/",domain=None,secure=False,httponly=False)
cookie
=““的名字(删除时也要使用)。
value
=””, cookie的值
max_age
=None
,过期时间(单位为秒)。距离现在多少秒后cookie将过期。
expires
=None
, 为datetime
类型。
path
="/"
, 默认在‘/’
表示在当前域名下的所有URL都有效。
domain
=None
, 设置cookie有效域名
secure
=False
,False
表示在http
下使用,True
表示在https
下使用
httponly
=False
,True
表示只能被浏览器读取,不能被js读取
设置回传给客户端 cookie 的相关配置
resp = make_response("success") # 设置响应体,成功创建了客户端cookie
resp.set_cookie("test", "test", max_age=3600) # 创建 test cookie,时长1小时
# 前面的"test"是cookie的键名,后面的是键值"test"
- 获取客户端的cookie
获取cookie,通过request.cookies
的方式, 返回的是一个字典,可以获取字典里的相应的值
cookie_1 = request.cookies.get("test")
可以从客户端请求中获取客户端的cookie信息
3.删除cookie
这里的删除只是让cookie过期,并不是直接删除cookie
删除cookie,通过delete_cookie()
的方式, 里面是cookie的名字
resp = make_response("del success") # 设置响应体,成功删除了客户端cookie
resp.delete_cookie("test")
对过期的 cookie 进行删除,否则过期的cookie还是会存在的。
完整代码演示:
from flask import Flask, make_response, request # 注意需导入 make_response
app = Flask(__name__)
@app.route("/set_cookies")
def set_cookie():
resp = make_response("success")
resp.set_cookie("cookiename", "cookievalue",max_age=3600)
return resp
@app.route("/get_cookies")
def get_cookie():
cookie_1 = request.cookies.get("cookiename") # 获取名字为test对应cookie的值
return cookie_1
@app.route("/delete_cookies")
def delete_cookie():
resp = make_response("del success")
resp.delete_cookie("test")
return resp
if __name__ == '__main__':
app.run(debug=True)
测试下cookie还存不存在
查看下删除cookie后,服务器的回传信息,按键盘上的F12
Ctrl+R
注意这里不是双击名称下的cookie,而是单击cookie。