Как создать сайт с поддержкой AMP
Данный документ описывает метод создания версии сайта Wagtail с поддержкой AMP и размещения её отдельно от основного сайта на префиксе URL. Он также описывает, как заставить Wagtail отображать изображения с тэгом <amp-img> при посещении пользователем страницы AMP-версии сайта.
Обзор
В следующем разделе мы добавим новую запись URL, которая указывает на внутренний просмотр Wagtail serve(), что приведет к повторному отображению всего сайта по префиксу /amp.
Затем мы добавим некоторые утилиты, которые позволят отслеживать, находится ли текущий запрос в версии сайта с префиксом /amp, без необходимости объекта запроса.
После этого мы добавим обработчик контекста шаблона, чтобы позволить проверять внутри шаблонов, какая версия сайта отображается.
Затем, наконец, мы изменим поведение тэга {% image %} для отображения тэгов <amp-img> при отображении AMP-версии сайта.
Создание второго дерева страниц
Мы можем отобразить весь сайт по другому префиксу, дублировав URL Wagtail в файле проекта urls.py и присвоив ему префикс. Это необходимо сделать до стандартного URL Wagtail, иначе система будет пытаться найти /amp как страницу:
# <project>/urls.py
urlpatterns += [
# Add this line just before the default ``include(wagtail_urls)`` line
path('amp/', include(wagtail_urls)),
path('', include(wagtail_urls)),
]
Если теперь открыть http://localhost:8000/amp/ в вашем браузере, вы должны увидеть главную страницу.
Обеспечение отображения страниц в режиме AMP
Теперь все страницы будут отображаться по префиксу /amp, но сейчас нет никакой разницы между AMP-версией и обычной версией.
Для внесения изменений нам нужно добавить способ определения URL, используемого для отображения страницы. Для этого нам нужно обернуть просмотр Wagtail serve() и установить локальную переменную для потока, чтобы указать всем последующим частям кода, что активен режим AMP.
Примечание
Почему локальная переменная для потока?
(можете пропустить эту часть, если вас это не интересует)
Изменение объекта request было бы наиболее распространенным способом сделать это. Однако рендеринг тега изображения выполняется в части Wagtail, которая не имеет доступа к запросу.
Локальные переменные для потока — это глобальные переменные, которые могут иметь разные значения для каждого потока. Так как каждый поток обрабатывает только один запрос за раз, мы можем использовать его как способ передачи данных, специфичных для этого запроса, без необходимости передачи объекта запроса повсюду.
Django использует локальные переменные для потока для отслеживания текущего активного языка для запроса.
Python реализует локальные переменные для потока через класс threading.local, но начиная с Django 3.x, несколько запросов могут обрабатываться в одном потоке, и поэтому локальные переменные для потока больше не будут уникальны для одного запроса. Поэтому Django предоставляет asgiref.Local в качестве прямой замены.
Теперь давайте создадим эту локальную переменную для потока и некоторые утилитарные функции для взаимодействия с ней. Сохраните этот модуль как amp_utils.py в приложении вашего проекта:
# <app>/amp_utils.py
from contextlib import contextmanager
from asgiref.local import Local
_amp_mode_active = Local()
@contextmanager
def activate_amp_mode():
"""
A context manager used to activate AMP mode
"""
_amp_mode_active.value = True
try:
yield
finally:
del _amp_mode_active.value
def amp_mode_active():
"""
Returns True if AMP mode is currently active
"""
return hasattr(_amp_mode_active, 'value')
Этот модуль определяет две функции:
-
activate_amp_mode— это контекстный менеджер, который можно вызывать с помощью синтаксиса Pythonwith. В теле инструкцииwithрежим AMP будет активен. -
amp_mode_active— это функция, которая возвращаетTrueпри активном режиме AMP.
Далее, нам нужно определить представление, которое оборачивает встроенное представление Wagtail serve и вызывает контекстный менеджер activate_amp_mode.
# <app>/amp_views.py
from django.template.response import SimpleTemplateResponse
from wagtail.views import serve as wagtail_serve
from .amp_utils import activate_amp_mode
def serve(request, path):
with activate_amp_mode():
response = wagtail_serve(request, path)
# Render template responses now while AMP mode is still active
if isinstance(response, SimpleTemplateResponse):
response.render()
return response
Затем нам нужно создать файл amp_urls.py в том же приложении:
# <app>/amp_urls.py
from django.urls import re_path
from wagtail.urls import serve_pattern
from . import amp_views
urlpatterns = [
re_path(serve_pattern, amp_views.serve, name='wagtail_amp_serve')
]
Наконец, нам нужно обновить основной файл проекта urls.py для использования этого нового файла URL для префикса /amp:
# <project>/urls.py
from myapp import amp_urls as wagtail_amp_urls
urlpatterns += [
# Change this line to point at your amp_urls instead of Wagtail's urls
path('amp/', include(wagtail_amp_urls)),
re_path(r'', include(wagtail_urls)),
]
После этого никакой заметной разницы в AMP-версии сайта не должно быть.
Напишите обработчик контекста шаблона, чтобы можно было проверить состояние AMP в шаблонах
Это необязательно, но стоит сделать, чтобы убедиться, что все работает.
Добавьте файл amp_context_processors.py в ваше приложение, содержащий следующее:
# <app>/amp_context_processors.py
from .amp_utils import amp_mode_active
def amp(request):
return {
'amp_mode_active': amp_mode_active(),
}
Теперь добавьте путь к этому обработчику контекста в ключ ['OPTIONS']['context_processors'] настроек TEMPLATES.
# Either <project>/settings.py or <project>/settings/base.py
TEMPLATES = [
{
...
'OPTIONS': {
'context_processors': [
...
# Add this after other context processors
'myapp.amp_context_processors.amp',
],
},
},
]
Теперь вы можете использовать переменную amp_mode_active в шаблонах. Например:
{% if amp_mode_active %}
AMP MODE IS ACTIVE!
{% endif %}
Использование другого шаблона страницы, когда активен режим AMP
Вероятно, вы не захотите использовать одни и те же шаблоны на сайте AMP, что и на обычном сайте. Давайте добавим немного логики, чтобы Wagtail использовал отдельный шаблон всякий раз, когда страница отображается с включенным AMP.
Мы можем использовать миксин, который позволяет повторно использовать логику для разных типов страниц. Добавьте следующее в конец файла amp_utils.py, который вы создали ранее:
# <app>/amp_utils.py
import os.path
...
class PageAMPTemplateMixin:
@property
def amp_template(self):
# Get the default template name and insert `_amp` before the extension
name, ext = os.path.splitext(self.template)
return name + '_amp' + ext
def get_template(self, request):
if amp_mode_active():
return self.amp_template
return super().get_template(request)
Теперь добавьте этот миксин к любой модели страницы, например:
# <app>/models.py
from .amp_utils import PageAMPTemplateMixin
class MyPageModel(PageAMPTemplateMixin, Page):
...
Когда активен режим AMP, вместо стандартного будет использоваться шаблон по адресу app_label/mypagemodel_amp.html.
Если у вас другой соглашение об именовании, вы можете переопределить атрибут amp_template в модели. Например:
# <app>/models.py
from .amp_utils import PageAMPTemplateMixin
class MyPageModel(PageAMPTemplateMixin, Page):
amp_template = 'my_custom_amp_template.html'
© 2014-present Torchbox Ltd and individual contributors.
All rights are reserved.
Licensed under the BSD License.
https://docs.wagtail.org/en/v3.0.3/advanced_topics/amp.html