如何计算 Pyramid 复合项目中的跨应用程序 URL?

How do I compute cross-app URLs in a Pyramid composite project?

我正在使用 Pyramid 开发一个由多个应用程序组成的大型网络项目,使用复合应用程序功能连接在一起,我想在我的主页上生成导航 links 以指向不同的应用。我的 INI 文件是这样开始的:

[composite:main]
use = egg:Paste#urlmap
/ = home
/app1 = myapp1
/app2 = myapp2

[app:home]
use = egg:myproject#home

[app:myapp1]
use = egg:myproject#myapp1

[app:myapp2]
use = egg:myproject#myapp2

...

在给定的应用程序中,我使用 request.route_url('view_name') 生成 URL 并且代码正确地将 //app1/app2 添加到任何 URL 在应用程序中由 config.add_route(...).

定义

我使用 home 应用程序作为 / 网站的登录页面,我想在 home 模板中执行类似 request.route_url('app1.index') 的操作以生成link 到 app1 中的 index 视图。但是,当我尝试这样做时,我从模板中得到 KeyError: 'No such route named app1.index'

我的解决方法是将路径硬编码到我的主页导航 links 中,但我不想这样做,因为这些路径已经在我的项目的 .ini 配置中定义。

有没有办法在金字塔中做到这一点?

没有标准的解决方案。我个人使用的方法是在我的配置文件中定义应用程序之间的交叉链接,我写了一些代码将它们作为静态路由自动注入到我的应用程序中(参见 config.add_route 上的 static=True),这允许你使用 request.route_url 生成应用程序外部的网址。

因此我构建了一个如下所示的配置:

[composite:main]
use = egg:Paste#urlmap
/ = home
/app1 = myapp1
/app2 = myapp2

[app:home]
use = egg:myproject#home
links =
    app1 /app1
    app2 /app2

[app:myapp1]
use = egg:myproject#myapp1
links =
    home /
    app2 /app2

[app:myapp2]
use = egg:myproject#myapp2
links =
    home /
    app1 /app1

您可能会觉得它乏味,但我喜欢它在每个应用程序的基础上提供的控件。您也可以在文件的 [DEFAULT] 部分定义它并在应用程序之间继承它。

我的想法是,此配置将允许我执行 request.route_url('app1')

我使用此代码(将其放入名为 app_links.py 的文件中并通过 config.include('.app_links'):

包含它
from urllib.parse import urlparse

from pyramid.settings import aslist

def link_pregenerator(request, elements, kwargs):
    kwargs['_app_url'] = request.host_url
    return elements, kwargs

def includeme(config):
    settings = config.get_settings()

    links = aslist(settings.get('links', ''), flatten=False)
    for name, pattern in (item.split(' ', 1) for item in links):
        parsed = urlparse(pattern)
        if parsed.hostname:
            config.add_route(name, pattern, static=True)
        else:
            config.add_route(
                name, pattern,
                pregenerator=link_pregenerator,
                static=True,
            )