【问题标题】:Looking for inverse of url_for in Flask在 Flask 中寻找 url_for 的逆
【发布时间】:2013-10-08 09:26:24
【问题描述】:

我正在使用FlaskFlask-RESTful 来构建一个REST API。在这个 API 中,我的一些资源包含与其他资源的 url 关系。

当对这些资源执行 POST 请求时,我发现我需要 Flask 的 url_for() 函数的逆函数来解析传入的 url。

例如,https://www.example.com/buildings 的 POST 可能包含以下 json:

{
  "address": "123 Lyall St",
  ...
  "owner": {
      "href": "https://www.example.com/users/21414512"
  },
  "tenant": {
      "href": "https://www.example.com/users/16324642"
  },
}

我想使用以下路径从ownertenant 中解析出id:

"https://www.example.com/users/<int:id>"

在 Flask 或 Werkzueg 中是否有方便的方法来执行此操作,或者我应该自己解析 url?能够重用已经定义好的路由就好了……

我找到了this 帖子,但它似乎没有描述如何在请求之外进行操作。

【问题讨论】:

标签: python json rest flask werkzeug


【解决方案1】:

创建测试请求上下文的最简单方法(感谢Leon Young):

with app.test_request_context(YOUR_URL) as request_ctx:
    url_rule = request_ctx.request.url_rule

但在创建请求上下文的背后都是有意义的:

from flask.testing import make_test_environ_builder

builder = make_test_environ_builder(app, YOUR_URL)
environ = builder.get_environ()
url_adapter = app.url_map.bind_to_environ(environ)
url_rule, view_args = url_adapter.match(return_rule=True)

如果没有原因检查协议和主机,您可以创建特殊的匹配方法:

from functools import partial

url_adapter = app.url_map.bind('localhost')
match = partial(url_adapter.match, return_rule=True)

并且在没有协议和主机的情况下使用它:

owner_url_rule, owner_view_args = match('/users/21414512')
tenant_url_rule, tenant_view_args = match('/users/16324642')

【讨论】:

    【解决方案2】:

    我使用下面的route_from函数:

    from flask.globals import _app_ctx_stack, _request_ctx_stack
    from werkzeug.urls import url_parse
    
    def route_from(url, method = None):
        appctx = _app_ctx_stack.top
        reqctx = _request_ctx_stack.top
        if appctx is None:
            raise RuntimeError('Attempted to match a URL without the '
                               'application context being pushed. This has to be '
                               'executed when application context is available.')
    
        if reqctx is not None:
            url_adapter = reqctx.url_adapter
        else:
            url_adapter = appctx.url_adapter
            if url_adapter is None:
                raise RuntimeError('Application was not able to create a URL '
                                   'adapter for request independent URL matching. '
                                   'You might be able to fix this by setting '
                                   'the SERVER_NAME config variable.')
        parsed_url = url_parse(url)
        if parsed_url.netloc is not "" and parsed_url.netloc != url_adapter.server_name:
            raise NotFound()
        return url_adapter.match(parsed_url.path, method)
    

    我是通过查看url_for 的实现并将其反转来写的。

    url 参数可以是完整的 URL,也可以只是路径信息部分。返回值是一个带有端点名称的元组和一个带有参数的dict

    免责声明:我尚未对其进行广泛测试。我计划最终将它作为拉取请求提交,但似乎从来没有完全测试它并编写一些单元测试。如果它不适合你,请告诉我!

    【讨论】:

    • 谢谢你这很好,但parsed_url.netloc is not "" 应该是!=
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-05-27
    • 1970-01-01
    • 2014-07-22
    • 2018-01-06
    • 2014-08-08
    • 1970-01-01
    相关资源
    最近更新 更多