Python Bottle 教程展示了如何使用 Python Bottle micro Web 框架在 Python 中创建简单的 Web 应用。

在线文档:https://www.osgeo.cn/bottle/tutorial.html

Bottle

Bottle 是用于 Python 的快速,简单且轻量级的 WSGI 微型网络框架。 它作为单个文件模块分发,除 Python 标准库外,没有其他依赖项。

Web 服务器网关接口(WSGI)是 Web 服务器的简单调用约定,用于将请求转发到以 Python 编程语言编写的 Web 应用或框架。

  • URL映射(Routing): 将URL请求映射到Python函数,支持动态URL,且URL更简洁。
  • 模板(Templates): 快速且pythonic的 内置模板引擎 ,同时支持 mako , jinja2 和 cheetah 等模板。
  • 基础功能(Utilities): 方便地访问表单数据,上传文件,使用cookie,查看HTTP元数据。
  • 服务器: 内置HTTP开发服务器并支持 paste, bjoern, gae, cherrypy 或任何其他 WSGI 功能强大的HTTP服务器。

Bottle 安装

  1. $ sudo pip3 install bottle

我们使用pip3工具安装 Bottle。

Bottle简单的例子

在下面的示例中,我们创建一个简单的 Bottle 应用。

  1. $ mkdir simple && cd simple
  2. $ touch simple.py

我们创建一个项目目录一个 Python 文件。

simple.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run
  3. @route('/message')
  4. def hello():
  5. return "Today is a beautiful day"
  6. run(host='localhost', port=8080, debug=True)

该示例向客户端发送一条消息。

  1. from bottle import route, run

我们导入route装饰器和run函数。 route装饰器用于将功能绑定到请求 URL。 run功能启动服务器实例。 默认情况下,它是开发服务器。

  1. @route('/message')
  2. def hello():
  3. return "Today is a beautiful day"

使用@route()装饰器,我们定义了一条路线。 路由是 URL 与 Web 服务器功能之间的映射。 在我们的例子中,该功能返回一条简单的文本消息。

  1. run(host='localhost', port=8080, debug=True)

我们以调试模式在端口 8080 上启动服务器。

  1. $ ./simple.py
  2. Bottle v0.12.13 server starting up (using WSGIRefServer())...
  3. Listening on http://localhost:8080/
  4. Hit Ctrl-C to quit.

我们启动开发服务器。

  1. $ curl localhost:8080/message
  2. Today is a beautiful day

我们使用curl工具创建一个请求。 服务器以一条简单消息响应。

Bottle JSON 响应

Web 应用通常以 JSON 格式发送响应。 Bottle 自动将 Python 词典转换为 JSON。

json_response.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run
  3. @route('/cars')
  4. def getcars():
  5. cars = [ {'name': 'Audi', 'price': 52642},
  6. {'name': 'Mercedes', 'price': 57127},
  7. {'name': 'Skoda', 'price': 9000},
  8. {'name': 'Volvo', 'price': 29000},
  9. {'name': 'Bentley', 'price': 350000},
  10. {'name': 'Citroen', 'price': 21000},
  11. {'name': 'Hummer', 'price': 41400},
  12. {'name': 'Volkswagen', 'price': 21600} ]
  13. return dict(data=cars)
  14. run(host='localhost', port=8080, debug=True)

该应用将有关汽车的数据作为 JSON 发送到客户端。

  1. return dict(data=cars)

Bottle 将 Python 字典转换为 JSON。

  1. $ curl localhost:8080/cars
  2. {"data": [{"name": "Audi", "price": 52642}, {"name": "Mercedes", "price": 57127},
  3. {"name": "Skoda", "price": 9000}, {"name": "Volvo", "price": 29000},
  4. {"name": "Bentley", "price": 350000}, {"name": "Citroen", "price": 21000},
  5. {"name": "Hummer", "price": 41400}, {"name": "Volkswagen", "price": 21600}]}

我们收到一个命名的 JSON 数组。

Bottle 获取请求

HTTP GET 方法请求指定资源的表示形式。 在 Bottle 中,我们可以使用@route@get装饰器映射 GET 请求。 从request.query检索数据。

GET 请求通常是默认的请求方法。

get_request.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run, request, get
  3. @get('/msg')
  4. def message():
  5. name = request.query.name
  6. age = request.query.age
  7. return "{0} is {1} years old".format(name, age)
  8. run(host='localhost', port=8080, debug=True)

该应用根据 GET 请求的数据构建一条消息。

  1. @get('/msg')
  2. def message():

message()函数通过/msg路径映射到 GET 请求。 @get('msg')装饰器等效于@route('msg', method='GET'),或更短的@route('msg')

  1. name = request.query.name
  2. age = request.query.age

我们从查询字符串中检索数据。

  1. $ curl "localhost:8080/greet?name=Peter&age=34"
  2. Peter is 34 years old

我们使用curl工具发出 GET 请求。 GET 请求是curl的默认请求。 我们将name和age参数添加到查询字符串。

Bottle 静态文件

使用static_file(),我们可以在 Bottle 中提供静态文件。

  1. $ mkdir botstat && cd botstat
  2. $ mkdir public
  3. $ touch public/home.html app.py

我们为应用创建目录和文件。

public/home.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Home page</title>
  7. </head>
  8. <body>
  9. <p>This is home page</p>
  10. </body>
  11. </html>

这是位于public目录中的主页。 静态资源的目录通常称为publicstatic

app.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run, static_file
  3. @route('/<filepath:path>')
  4. def server_static(filepath):
  5. return static_file(filepath, root='./public/')
  6. run(host='localhost', port=8080, debug=True)

在此示例中,我们提供静态文件。 为了获得主页,我们必须导航到localhost:8080/home.html

  1. @route('/<filepath:path>')

filepath:path是仅允许出现在包含斜杠的路径中的字符的过滤器。

  1. return static_file(filepath, root='./public/')

通过static_file()功能,我们可以提供静态文件。 静态文件所在的目录在root参数中指定。

Bottle 过滤器

包含通配符的路由称为动态路由(与静态路由相对)。 它们可以同时匹配多个 URL。 通配符由括在尖括号中的名称组成(例如<名称>),并且可以接受一个或多个字符,直到下一个斜杠为止。

过滤器可用于定义更特定的通配符。

  • :int 匹配(带符号)数字
  • :float 匹配十进制数字
  • :path 路径段中允许使用的数学字符
  • :re 允许指定自定义正则表达式

filters.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run
  3. @route('/app/<myid:int>/')
  4. def provide(myid):
  5. return "Object with id {} returned".format(myid)
  6. @route('/app/<name:re:[a-z]+>/')
  7. def provide(name):
  8. return "Name {} given".format(name)
  9. run(host='localhost', port=8080, debug=True)

该示例使用整数过滤器和正则表达式过滤器。

  1. $ curl localhost:8080/app/3/
  2. Object with id 3 returned

在这里,我们向路径添加一个整数。

Bottle 例子

在下面的示例中,我们将表单发送到 Bottle 应用。

  1. $ mkdir simple_form && cd simple_form
  2. $ mkdir public
  3. $ touch public/index.html simple_form.py

我们为应用创建目录和文件。

public/index.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Home page</title>
  7. </head>
  8. <body>
  9. <form method="post" action="doform">
  10. <div>
  11. <label for="name">Name:</label>
  12. <input type="text" id="name" name="name">
  13. </div>
  14. <div>
  15. <label for="occupation">Occupation:</label>
  16. <input type="text" id="occupation" name="occupation">
  17. </div>
  18. <button type="submit">Submit</button>
  19. </form>
  20. </body>
  21. </html>

在 HTML 文件中,我们有一个表单标签。 该表格包含两个输入字段:名称和职业。

simple_form.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run, post, request, static_file
  3. @route('/')
  4. def server_static(filepath="index.html"):
  5. return static_file(filepath, root='./public/')
  6. @post('/doform')
  7. def process():
  8. name = request.forms.get('name')
  9. occupation = request.forms.get('occupation')
  10. return "Your name is {0} and you are a(n) {1}".format(name, occupation)
  11. run(host='localhost', reloader=True, port=8080, debug=True)

simple_form.py文件中,我们提供一个表格并处理该表格。

  1. @route('/')
  2. def server_static(filepath="index.html"):
  3. return static_file(filepath, root='./public/')

对于根路径(/),我们从public目录提供index.html

  1. @post('/doform')
  2. def process():
  3. name = request.forms.get('name')
  4. occupation = request.forms.get('occupation')
  5. return "Your name is {0} and you are a(n) {1}".format(name, occupation)

在这里,我们处理表格。 我们使用@post装饰器。 我们从request.forms获取数据并构建消息字符串。

Bottle 错误处理程序

可以使用@error装饰器创建自定义错误页面。

error_handler.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run, error
  3. @route('/app/<myid:int>')
  4. def provide(myid):
  5. return "Object with id {} returned".format(myid)
  6. @error(404)
  7. def error404(error):
  8. return '404 - the requested page could not be found'
  9. run(host='localhost', port=8080, debug=True)

在此示例中,我们在自定义错误处理程序中处理 404 错误。

  1. @error(404)
  2. def error404(error):
  3. return '404 - the requested page could not be found'

@error装饰器将错误代码作为参数。

  1. $ curl localhost:8080/app/Peter
  2. 404 - the requested page could not be found

我们尝试访问未定义的路由; 我们会收到自定义错误消息。

Bottle MongoDB 示例

在以下示例中,我们从 MongoDB 数据库以 JSON 形式返回数据。

create_cars.py

  1. #!/usr/bin/python3
  2. from pymongo import MongoClient
  3. cars = [ {'name': 'Audi', 'price': 52642},
  4. {'name': 'Mercedes', 'price': 57127},
  5. {'name': 'Skoda', 'price': 9000},
  6. {'name': 'Volvo', 'price': 29000},
  7. {'name': 'Bentley', 'price': 350000},
  8. {'name': 'Citroen', 'price': 21000},
  9. {'name': 'Hummer', 'price': 41400},
  10. {'name': 'Volkswagen', 'price': 21600} ]
  11. client = MongoClient('mongodb://localhost:27017/')
  12. with client:
  13. db = client.testdb
  14. db.cars.insert_many(cars)

使用此脚本,我们创建一个 Mongo 集合。 有关在 Python 中使用 MongoDB 的更多信息,请参考 PyMongo 教程。

bottle_mongo.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run, HTTPResponse
  3. from pymongo import MongoClient
  4. import json
  5. client = MongoClient('mongodb://localhost:27017/')
  6. @route('/cars')
  7. def getcars():
  8. db = client.testdb
  9. cars = list(db.cars.find({}, {'_id': 0}))
  10. if cars:
  11. return json.dumps(cars)
  12. else:
  13. raise HTTPResponse(status=204)
  14. run(host='localhost', port=8080, debug=True)

该示例从 Mongo 集合返回数据作为 JSON。

  1. client = MongoClient('mongodb://localhost:27017/')

创建一个MongoClient实例。

  1. db = client.testdb
  2. cars = list(db.cars.find({}, {'_id': 0}))

我们从两个字段中检索所有数据; 我们排除_id字段。

  1. if cars:
  2. return json.dumps(cars)
  3. else:
  4. raise HTTPResponse(status=204)

如果有数据,我们将使用json.dumps()将其转换为 JSON,然后将其返回给客户端。 否则,我们会发送 204 状态代码。

Bottle 模板示例

模板引擎是一个旨在将模板与数据模型结合以生成结果文档的库。 默认情况下,Bottle 使用简单的模板引擎。

  1. $ mkdir botview && cd botview
  2. $ mkdir views
  3. $ touch views/show_cars.tpl app.py

我们为应用创建目录和文件。

views/show_cars.tpl

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Cars</title>
  7. </head>
  8. <body>
  9. <table>
  10. <tr>
  11. <th>Name</th>
  12. <th>Price</th>
  13. </tr>
  14. % for car in cars:
  15. <tr>
  16. <td>{{car['name']}}</td>
  17. <td>{{car['price']}}</td>
  18. </tr>
  19. % end
  20. </table>
  21. </body>
  22. </html>

在此模板中,我们浏览接收到的cars对象并从中生成一个表。 模板文件位于views目录中。

app.py

  1. #!/usr/bin/env python3
  2. from bottle import route, run, template, HTTPResponse
  3. from pymongo import MongoClient
  4. client = MongoClient('mongodb://localhost:27017/')
  5. @route('/cars')
  6. def getcars():
  7. db = client.testdb
  8. data = db.cars.find({}, {'_id': 0})
  9. if data:
  10. return template('show_cars', cars=data)
  11. else:
  12. return HTTPResponse(status=204)
  13. run(host='localhost', port=8080, debug=True)

在应用中,我们从 MongoDB 集合中检索数据。 我们使用template()功能将模板文件与数据结合在一起。

疑难解答

英文版: https://zetcode.com/python/bottle/

python——bottle框架开发采坑记录

https://blog.csdn.net/Little_jcak/article/details/124185758

bottle框架使用一个小坑-获取中文参数乱码 https://blog.csdn.net/feitianxuxue/article/details/102898800