[toc]
配置Pycharm使用SSH虚拟环境中的解释器
找到解释器位置
Pycharm中添加新的SSH解释器,输入服务器账号密码后找到该目录下的python
配置远程同步文件夹
最后成功看到Hello, World
实验简介
本实验将详细介绍 Flask 的路由,并通过一些实例来证明。
知识点
- 路由介绍
- 变量规则
- 重定向
- 构建 URL
- HTTP 方法
路由介绍
现代 Web 应用程序使用有意义的 URLs 去帮助用户。如果一个网站使用有意义的 URL 能够让用户记住并且直接访问这个页面,那么用户会更有可能再一次访问该网站。
正如上面所说,route
装饰器是用于把一个函数绑定到一个 URL 上。修改 /home/project/hello.py
文件的代码如下所示:
from flask import Flask
app = Flask(__name__)
# 如果访问根目录 '/' ,返回 Index Page
@app.route('/')
def index():
return 'Index Page'
# 如果访问 '/hello' ,返回 Hello, World!
@app.route('/hello')
def hello():
return 'Hello, World!'
因为章节跳转过程使我们自动退出了虚拟环境,所有我们首先激活虚拟环境:
source venv/bin/activate
然后在终端执行如下命令启动服务:
export FLASK_APP=hello.py
export FLASK_ENV=development
flask run -h 0.0.0.0 -p 8080
点击右侧工具栏的 Web 服务按钮,浏览器页面会显示 Index Page
:
如果访问地址 http://xxx/hello
,浏览器页面会显示 Hello, World!
:
这样就实现了通过访问不同的 URL 地址从而响应不同的页面。
不仅如此!你可以动态地构造 URL 的特定部分,也可以在一个函数上绑定多个不同的规则。
我的结果:
不太明白这个为啥后面的函数高亮就出问题了
变量规则
为了给 URL 增加变量的部分,你需要把一些特定的字段标记成 <variable_name>
。这些特定的字段将作为参数传入到你的函数中。当然也可以指定一个可选的转换器通过规则 <converter:variable_name>
将变量值转换为特定的数据类型。 在 /home/project/hello.py
文件中添加如下的代码:
@app.route('/user/<username>')
def show_user_profile(username):
# 显示用户名
return 'User {}'.format(username)
@app.route('/post/<int:post_id>')
def show_post(post_id):
# 显示提交整型的用户"id"的结果,注意"int"是将输入的字符串形式转换为整型数据
return 'Post {}'.format(post_id)
@app.route('/path/<path:subpath>')
def show_subpath(subpath):
# 显示 /path/ 之后的路径名
return 'Subpath {}'.format(subpath)
按照前面的方式启动应用,逐个访问地址:
当访问 https://xxx/user/shiyanlou
时,页面显示为 User shiyanlou
。
当访问 https://xxx/post/3
时,页面显示为 Post 3
。用户在浏览器地址栏上输入的都是字符串,但是在传递给 show_post
函数处理时已经被转换为了整型。
当访问 https://xxx/path/file/A/a.txt
时,页面显示为 Subpath file/A/a.txt
。
注意:上面几个链接中的https://xxx
是指你点击右侧工具栏“Web 服务”自动生成的链接
转换器的主要类型如下:
类型 | 含义 |
---|---|
string | 默认的数据类型,接受没有任何斜杠“/”的字符串 |
int | 接受整型 |
float | 接受浮点类型 |
path | 和 string 类似,但是接受斜杠“/” |
uuid | 只接受 uuid 字符串 |
我的结果:
唯一 URLs / 重定向行为
Flask 的 URL 规则是基于 Werkzeug 的 routing 模块。该模块背后的思路是基于 Apache 和早期的 HTTP 服务器定下先例确保优雅和唯一的 URL。
以这两个规则为例,在 /home/project/hello.py
文件中添加如下的代码:
@app.route('/projects/')
def projects():
return 'The project page'
@app.route('/about')
def about():
return 'The about page'
虽然它们看起来确实相似,但它们结尾斜线的使用在 URL 定义中不同。
第一种情况中,规范的 URL 指向 projects 尾端有一个斜线 /
。这种感觉很像在文件系统中的文件夹。访问一个结尾不带斜线的 URL 会被 Flask 重定向到带斜线的规范 URL 去。当访问 https://xxx/projects/
时,页面会显示 The project page
。
然而,第二种情况的 URL 结尾不带斜线,类似 UNIX-like 系统下的文件的路径名。此时如果访问结尾带斜线的 URL 会产生一个 404 “Not Found”
错误。当访问 https://xxx/about
时,页面会显示 The about page
;但是当访问 https://xxx/about/
时,页面就会报错 Not Found
。
当用户访问页面忘记结尾斜线时,这个行为允许关联的 URL 继续工作,并且与 Apache 和其它的服务器的行为一致,反之则不行,因此在代码的 URL 设置时斜线只可多写不可少写;另外,URL 会保持唯一,有助于避免搜索引擎索引同一个页面两次。
构建 URL
去构建一个 URL 来匹配一个特定的函数可以使用 url_for()
方法。它接受函数名作为第一个参数,以及一些关键字参数,每一个关键字参数对应于 URL 规则的变量部分。未知变量部分被插入到 URL 中作为查询参数。
为什么你要构建 URLs 而不是在模版中硬编码呢?这里有几个理由:
- 反向构建通常比硬编码更具备描述性。
- 它允许你一次性修改 URL,而不是到处找 URL 修改。
- 构建 URL 能够显式地处理特殊字符和
Unicode
转义,因此你不必去处理这些。 - 如果你的应用不在 URL 根目录下(比如,在
/myapplication
而不在/
),url_for()
将会适当地替你处理好。
在 Python shell 交互式命令行下运行如下代码:
>>> from flask import Flask, url_for
>>> app = Flask(__name__)
>>> @app.route('/')
... def index():
... return 'index'
...
>>> @app.route('/login')
... def login():
... return 'login'
...
>>> @app.route('/user/<username>')
... def profile(username):
... return '{}\'s profile'.format(username)
...
>>> with app.test_request_context():
... print(url_for('index'))
... print(url_for('login'))
... print(url_for('login', next='/'))
... print(url_for('profile', username='John Doe'))
...
/
/login
/login?next=%2F # 对字符串进行了转义,未知变量部分被当做查询参数
/user/John%20Doe
test_request_context()
方法告诉 Flask 表现得像是在处理一个请求,即使我们正在通过 Python shell 交互。大家可以仔细分析一下该函数的打印结果。
这部分讲解的有点迷,可以参考w3cschool的Flask URL构建
HTTP 方法
HTTP (也就是 Web 应用协议) 有不同的方法来访问 URLs 。默认情况下,路由只会响应 GET 请求,但是能够通过给 route()
装饰器提供 methods
参数来改变。这里是一个例子:
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
do_the_login() # 如果是 POST 方法就执行登录操作
else:
show_the_login_form() # 如果是 GET 方法就展示登录表单
如果使用 GET
方法,HEAD
方法将会自动添加进来。你不必处理它们。也能确保 HEAD
请求会按照 HTTP RFC (文档在 HTTP 协议里面描述) 要求来处理,因此你完全可以忽略这部分 HTTP 规范。同样地,自从 Flask 0.6 后,OPTIONS
方法也能自动为你处理。
也许你并不清楚 HTTP 方法是什么?别担心,这里有一个 HTTP 方法的快速入门以及为什么它们重要:
HTTP
方法(通常也称为“谓词”)告诉服务器客户端想要对请求的页面做什么。
下面这些方法是比较常见的:
- GET:浏览器通知服务器只获取页面上的信息并且发送回来。这可能是最常用的方法。
- HEAD:浏览器告诉服务器获取信息,但是只对头信息感兴趣,不需要整个页面的内容。应用应该处理起来像接收到一个 GET 请求但是不传递实际内容。在 Flask 中你完全不需要处理它,底层的 Werkzeug 库会为你处理的。
- POST:浏览器通知服务器它要在 URL 上提交一些信息,服务器必须保证数据被存储且只存储一次。这是 HTML 表单通常发送数据到服务器的方法。
- PUT:同 POST 类似,但是服务器可能触发了多次存储过程,多次覆盖掉旧值。现在你就会问这有什么用,有许多理由需要如此去做。考虑下在传输过程中连接丢失:在这种情况下浏览器和服务器之间的系统可能安全地第二次接收请求,而不破坏其它东西。该过程操作 POST 方法是不可能实现的,因为它只会被触发一次。
- DELETE:移除给定位置的信息。
- OPTIONS:给客户端提供一个快速的途径来指出这个 URL 支持哪些 HTTP 方法。从 Flask 0.6 开始,自动实现了该功能。
现在在 HTML4 和 XHTML1 中,表单只能以 GET 和 POST 方法来提交到服务器。在 JavaScript 和以后的 HTML 标准中也能使用其它的方法。同时,HTTP 最近变得十分流行,浏览器不再是唯一使用 HTTP 的客户端。比如许多版本控制系统使用 HTTP。
总结
本节讲解了 Flask 的路由,我们可以给 URL 添加规则,也可以动态地构建 URL 。
练习
- 请开发一个小应用,URL 地址输入
https://xxx/name
(https://xxx
是点击“Web 服务”自动生成的链接,name 表示你输入的名字),访问页面会显示 name。 - 请完成一个应用,当 URL 是
https://xxx/sum/a/b
时,其中a
和b
都是数字,服务器返回它们的和。
参考答案
练习题 1 的答案:
from flask import Flask
app = Flask(__name__)
@app.route('/<username>')
def get_name(username):
return username
练习题 2 的答案:
from flask import Flask
app = Flask(__name__)
@app.route('/sum/<int:a>/<int:b>')
def get_sum(a,b):
return '{0} + {1} = {2}'.format(a,b,a+b)