#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-файла и наследования оттуда. Если я в конечном итоге сделаю это, я сообщу здесь о том, как это работает.