如何在Bottle中从路径获取参数?

5 投票
4 回答
5198 浏览
提问于 2025-04-18 04:44

当我执行这个网址时:

http://domain:8081/forum?id=2&page=26

用这段代码:

@route('/forum')
def display_forum():
   forum_id = request.query.id
   page = request.query.page or '1'
   return template('Forum ID: {{id}} (page {{page}})', id=forum_id, page=page)

网页上返回了 论坛 ID: 2 (第 26 页)

我想通过调用一个动态的 REST URL 来获得相同的结果。这个网址可以是 http://domain:8081/forum/2/26 或者 http://domain:8081/forum/city/place/day/hour

参数的数量并不是固定的。我在 Bottle 的文档中看到了一些想法,可能可以用类似通配符过滤器 :path 的东西。

4 个回答

0

我的解决办法是把表单里的值和查询里的值结合起来,形成一个统一的接口。

def merge_dicts(*args):
    result = {}
    for dictionary in args:
        result.update(dictionary)
    return result

payload = merge_dicts(dict(request.forms), dict(request.query.decode()))
id = payload['id']
page = payload['page']
0

我会使用:path这个通配符过滤器,就像你提到的那样。在你的例子中,你提供了带有键值对的查询参数,并询问如何用网址路径来实现同样的功能,但只使用值,并且没有固定参数数量的限制。

比如说:

/forum?id=2&page=26

/forum/2/6

因为我们不想限制参数的数量,我觉得在网址路径中以成对的方式提供键是有道理的。

比如:

/forum/id/2/page/26/city/chicago/place/opera/day/monday/hour/2:20pm

然后我会根据这个进行解析:

from bottle import route, run, request, template
import re

@route("/forum/<url_paths:path>", method=["GET", "POST"])
def display_forum(url_paths=None):
    # -- parse the paths as pairs of /key/value/key/value...
    match = re.compile(r"/", re.VERBOSE)
    items = map(str, match.split(url_paths))
    url_params = dict(zip(items, items))

    # -- check for any GET or POST parameters and save as dict(),
    req_params = {k:v for (k,v) in request.params.items()}

    # -- merge the url_params with req_params into one dictionary object
    params = url_params | req_params

    # -- parse forum_id and page
    if params:
        forum_id = params.pop("id") if params.get("id") else "NA"
        page = params.pop("page") if params.get("page") else "1"
        tpl = """
        Forum ID: {{id}} (page {{page}})
        % for (key, value) in params.items():
            {{key}}: {{value}}
        %end

        """
        return template(tpl, id=forum_id, page=page, params=params)
    return "please provide url paths, query params, or post data"

run(host="0.0.0.0", port=8081, reloader=True)

示例请求

仅网址路径

❯ curl "http://127.0.0.1:8081/forum/city/Miami/place/Dog%20Park/day/Wednesday/hour/8:20pm/id/8/page/7"

        Forum ID: 8 (page 7)
            city: Miami
            place: Dog Park
            day: Wednesday
            hour: 8:20pm

网址路径和查询参数

❯ curl "http://127.0.0.1:8081/forum/city/Chicago/place/Opera%20House/day/Saturday/hour/6:20pm?id=2&page=26"

        Forum ID: 2 (page 26)
            city: Chicago
            place: Opera House
            day: Saturday
            hour: 6:20pm

网址路径和POST参数

❯ curl -X POST "http://127.0.0.1:8081/forum/event/Yoga/city/Philadelphia/place/Gym/day/Tuesday/hour/8:00am" -d "id=2&page=3"

        Forum ID: 2 (page 3)
            event: Yoga
            city: Philadelphia
            place: Gym
            day: Tuesday
            hour: 8:00am

网址路径和POST表单字段

❯ curl -X POST "http://127.0.0.1:8081/forum/event/Concert/city/Virginia%20Beach/place/GTE%20Amphitheatre/day/Friday/hour/7:20pm/price/\$65.00" -F "id=3" -F "page=16"

        Forum ID: 3 (page 16)
            event: Concert
            city: Virginia Beach
            place: GTE Amphitheatre
            day: Friday
            hour: 7:20pm
            price: $65.00
0

使用参数

@route ('/forum/forum_id=:forum_id&page=:page')
def display_forum(forum_id,page):
   forum_id = request.query.id
   page = request.query.page or '1'
   return template('Forum ID: {{id}} (page {{page}})', id=forum_id, page=page)
3

这个方法不能无限制地扩展到很多条路线,但像这样的做法是可行的。

@route('/forum/<first>')
def test(first):
    return first

@route('/forum/<first>/<second>')
def test(first, second):
    return first, second

@route('/forum/<first>/<second>/<third>')
def test(first, second, third):
    return first, second, third

@route('/forum/<first>/<second>/<third>/<fourth>')
def test(first, second, third, fourth):
    return first, second, third, fourth

撰写回答