Как мне вычислить URL-адреса для разных приложений в составном проекте Pyramid?

#python #url-routing #pyramid

#python #url-маршрутизация #пирамида

Вопрос:

Я использую Pyramid для разработки большого веб-проекта, состоящего из нескольких приложений, объединенных вместе с помощью функции составного приложения, и я хочу создать навигационные ссылки на моей домашней странице, чтобы указывать на разные приложения. Мой 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 приложение в качестве целевой страницы для веб-сайта at / , и я хочу сделать что-то вроде request.route_url('app1.index') в home шаблоне, чтобы сгенерировать ссылку на index представление app1 . Однако, когда я пытаюсь это сделать, я получаю KeyError: 'No such route named app1.index' из шаблона.

Мой обходной путь — жестко запрограммировать пути в ссылках навигации на моей домашней странице, но я бы предпочел этого не делать, поскольку эти пути уже определены в конфигурации .ini моего проекта.

Есть ли способ сделать это в Pyramid?

Ответ №1:

Существует нестандартное решение. Подход, который я использовал лично, заключается в определении перекрестных ссылок между приложениями в моем конфигурационном файле, и я написал некоторый код для автоматического внедрения их в мои приложения в виде статических маршрутов (см. static=True Далее config.add_route ), который позволяет вам использовать request.route_url для генерации 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,
            )
  

Комментарии:

1. Большое спасибо за ваш ответ @michael-merickel. Я попробую это решение позже на этой неделе. (В качестве примечания, поскольку вы упомянули раздел [ПО УМОЛЧАНИЮ], у меня не было большого успеха с этим в моем составном приложении. Я начал задаваться вопросом, не пропускается ли [DEFAULT] в составных настройках. Полагаю, я должен задать это в другом вопросе SO.)

2. Значения в разделе по умолчанию не добавляются автоматически в разделы вашего приложения, вам нужно использовать специальный синтаксис «get local_name = global_name», чтобы получить значение, или вам нужно объединить его самостоятельно в главном, где вы получите оба (global_config, **app_settings) . Вы можете прочитать документы PasteDeploy, чтобы узнать больше о том, как все это работает.

3. Я принимаю это как ответ, поскольку он выполняет свою работу, а также помогает мне лучше понять систему конфигурации пирамиды. Мне нравится идея определения links в [DEFAULT] разделе INI-файла и наследования оттуда. Если я в конечном итоге сделаю это, я сообщу здесь о том, как это работает.