Как получить удаленный пользовательский агент внутри шаблона Genshi при использовании Trac и WSGI?

Я пытаюсь настроить веб-сайт управления проектами Trac и столкнулся с интересной проблемой. В проекте есть набор изображений в форматах SVG и PNG. Изображения SVG имеют множество преимуществ, включая несколько гиперссылок и меньший передаваемый размер по сравнению с PNG, который больше и может ссылаться только на один документ.

Я понимаю, что можно использовать jQuery для обнаружения пользовательского агента после загрузки страницы и замены PNG версией изображения SVG, но это приводит к тому, что PNG отправляется всем клиентам. Я также могу попросить Genshi заменить PNG на SVG для всех клиентов, а затем использовать jQuery, чтобы вернуть PNG, но возникает та же проблема. Я мог бы использовать jQuery для вставки соответствующих изображений для всех клиентов, но это кажется глупым требовать, чтобы клиент делал то, что должен делать сервер.

Есть ли способ получить информацию о браузере внутри шаблона Genshi? Это немного сложнее, чем просто вызывать переменные среды, потому что я запускаю Trac с использованием WSGI. Я просмотрел вывод repr(locals()) и не увидел ничего похожего на решение моей проблемы. Я также хотел бы избежать изменения исходного кода Trac.


person Pridkett    schedule 06.12.2009    source источник


Ответы (2)


user_agent = environ.get('HTTP_USER_AGENT', None)

Или, если environ обернут каким-то объектом Request:

user_agent = request.user_agent

Кстати, вам, вероятно, следует посмотреть заголовок HTTP_ACCEPT вместо HTTP_USER_AGENT, чтобы узнать, какое представление должно быть отправлено.

person jfs    schedule 06.12.2009
comment
Да, в среде CGI или внутри приложения WSGI я мог бы сделать это, но environ внутри Genshi пуст, и я не могу понять, где/если объект запроса передается в Genshi из Trac/WSGI. Кроме того, HTTP_ACCEPT, вероятно, не подходит, потому что некоторые браузеры лгут, говоря, что они могут принимать SVG, но делают это плохо — я смотрю на вас, Chrome! Что дают гигантские белые коробки для фона‽ - person Pridkett; 06.12.2009
comment
@Pridkett: найдите имя шаблона в источнике трассировки и передайте туда необходимые переменные в коде рендеринга. - person jfs; 06.12.2009
comment
Я пытаюсь избежать изменения исходного кода Trac. Я шел по этому пути слишком много раз и не хочу беспокоиться об управлении различными патчами, даже очень простыми. - person Pridkett; 07.12.2009

Итак, я немного покопался в этом вопросе, не просматривая исходный код, а написав собственный обработчик Genshi, который выдает рекурсивные repr() каждого элемента в локальных (с помощью предыдущий вопрос, в котором говорилось о том, как распечатать все переменные в области видимости). Изначально я пропустил объект req. Похоже, это так же просто, как использовать req.environ['HTTP_USER_AGENT']. Проблема заключалась в том, чтобы найти объект req в первую очередь. Просматривая исходный код, я до сих пор не могу найти, где именно создаются экземпляры шаблонов, так что это оказывается намного проще и лучше, чем патч.

Для полноты картины вот фрагмент шаблона Genshi, который я использовал для замены логотипа только для более новых версий браузеров на основе Gecko. Это немного хакерски и, вероятно, неоптимально, но оно работает и не отправляет SVG в браузеры, которые лгут и говорят, что они «похожи на Gecko», но не могут правильно отображать SVG — да, я смотрю на вас, Webkit.

<py:if test="'Gecko/' in req.environ['HTTP_USER_AGENT'] and [int(x.split('/')[1]) for x in req.environ['HTTP_USER_AGENT'].split() if x.startswith('Gecko')][0] &gt; 20080101">
  <div py:match="div[@id='header']">
    <object type="image/svg+xml" id="svgLogo" data="${href.chrome('site/logo.svg')}" style="width=${chrome['logo']['width']}px; height=${chrome['logo']['height']}px;"></object>
  </div>
</py:if>
person Pridkett    schedule 07.12.2009