LaVOZs

The World’s Largest Online Community for Developers

'; python - How do I compute cross-app URLs in a Pyramid composite project? - LavOzs.Com

I'm using Pyramid to develop a large web project comprised of multiple apps, joined together using the composite app feature, and I want to generate navigation links on my home page to point to the different apps. My INI file starts like this:

[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

...

Within a given app, I use request.route_url('view_name') to generate URLs and the code correctly prepends / or /app1 or /app2 to whatever URL is defined within the application by config.add_route(...).

I use the home app as the landing page for the website at /, and I want to do something like request.route_url('app1.index') within a home template to generate a link to the index view in app1. When I try this, however, I get KeyError: 'No such route named app1.index' from the template.

My workaround is to hard-code the paths into my home page nav links, but I'd rather not do this, since those paths are already defined in my project's .ini configuration.

Is there a way to do this in Pyramid?

There is a not a standard solution. The approach I have used personally is to define cross-links between apps in my config file and I wrote some code to automatically inject them into my apps as static routes (see static=True on config.add_route) which allows you to use request.route_url to generate urls external to your app.

Thus I build a config that looks like this:

[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

You might find it tedious but I like the control it provides on a per-app basis. You could alternatively probably define this in the [DEFAULT] section of the file and inherit it between apps.

The idea is that this config will allow me to do request.route_url('app1').

I use this code (place it into a file named something like app_links.py and include it via 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,
            )
Related
Pyramid project structure
How to ignore repeated slashes in Pyramid
Pyramid: extend query string for every URL constructed by route_url
Is there a way to link a static site to Pyramid app without being part of Pyramid?
How to direct to a webpage in urls.py without using a view
uWSGI: How can I mount a paste-deploy (Pyramid) app?
Optional URL parameter on Pyramid route
Django - creating a main page without an extension with request processing (not direct to template)
Prevent automatic passing of URL parameter in Razor Pages
django url patterns for project with multiple apps