序言
在学习Miguel Grinberg的“使用 Python 和 Flask 设计 RESTful API”一文中,在“优化web service接口”一节中,遇见flask的url_for函数,当时不解其意,查阅资料后,记录,以便学习。
正文
原文中的API会让客户端在任务标识返回后去构造 URIs。这对于服务器十分简单,但作者打算不直接返回任务的 ids,而是直接返回控制这些任务的完整的 URI,以便客户端可以随时使用这些 URIs。
在这里作者构造了一个辅助函数生成一个 “公共” 版本任务发送到客户端。
from flask import url_for
def make_public_task(task):
new_task = {}
for field in task:
if field == 'id':
new_task['uri'] = url_for('get_task', task_id=task['id'], _external=True)
else:
new_task[field] = task[field]
return new_task
这里做的事是从数据库中取出任务并且创建一个新的任务,这个任务的 id 字段被替换成通过 Flask 的 url_for 生成的 uri 字段。当返回所有的任务列表的时候,在发送到客户端之前会通过这个函数进行处理。
以下是通过GET方法查询所有任务的代码。
@app.route('/todo/api/v1.0/tasks', methods=['GET'])
def get_tasks():
return jsonify({'tasks': map(make_public_task, tasks)})
在这里贴上作者在url_for中使用的“get_task”代码。
@app.route('/todo/api/v1.0/tasks/<int:task_id>', methods=['GET'])
def get_task(task_id):
task = filter(lambda t: t['id'] == task_id, tasks)
if len(task) == 0:
abort(404)
return jsonify({'task': task[0]})
以下是从客户端获取任务列表时候得到的数据。
$ curl -i http://localhost:5000/todo/api/v1.0/tasks
HTTP/1.0 200 OK
Content-Type: application/json
Content-Length: 406
Server: Werkzeug/0.8.3 Python/2.7.3
Date: Mon, 20 May 2013 18:16:28 GMT
{
"tasks": [
{
"title": "Buy groceries",
"done": false,
"description": "Milk, Cheese, Pizza, Fruit, Tylenol",
"uri": "http://localhost:5000/todo/api/v1.0/tasks/1"
},
{
"title": "Learn Python",
"done": false,
"description": "Need to find a good Python tutorial on the web",
"uri": "http://localhost:5000/todo/api/v1.0/tasks/2"
}
]
}
然后我们来讲讲url_for函数。
url_for(endpoint, **values)接收这些参数,使用所提供的方法生成给定端点的URL。例如,最简单的
#!flask/bin/python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def index():
return "Hello, World!"
if __name__ == '__main__':
app.run(debug=True)
当在程序中调用url_for(‘index’),则会返回/
如果调用url_for(‘index’, _external=True) 返回的则是绝对地址,在这个示例中是http://localhost:5000/
现在上面的url_for(‘get_task’, task_id=task[‘id’], _external=True)就好理解了,从get_task这个函数中获取到绝对地址,把获取到的task[‘id’]的值赋值给 task_id,从而得到了tasks中的字典的新键值对”uri”: “http://localhost:5000/todo/api/v1.0/tasks/1“。