Как создать сайт с поддержкой AMP
В этом документе описан способ создания версии сайта Wagtail с поддержкой AMP и размещения ее отдельно от основного сайта по префиксу URL. Также описано, как сделать так, чтобы Wagtail рендерил изображения с тэгом <amp-img> при посещении страницы AMP-версии сайта.
Обзор
В следующем разделе мы добавим новую запись URL, которая указывает на внутренний serve() вид Wagtail, что приведет к повторному рендерингу всего сайта по префиксу /amp.
Затем мы добавим некоторые утилиты, которые позволят нам отслеживать, находится ли текущий запрос в /amp префиксной версии сайта, не используя объект запроса.
После этого мы добавим обработчик контекста шаблонов, чтобы иметь возможность проверять из шаблонов, какая версия сайта рендерится.
И, наконец, мы изменим поведение тэга {% image %} для рендеринга тэгов <amp-img> при рендеринге AMP-версии сайта.
Создание второй иерархии страниц
Мы можем отображать весь сайт по другому префиксу, дублируя Wagtail URL в файле проекта 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, который использовался для рендеринга страницы. Для этого мы должны обернуть serve() вид Wagtail и установить локальную переменную потока, чтобы указать всем последующим частям кода, что режим 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.
Далее, нам нужно определить представление, которое обертывает встроенный serve вид Wagtail и вызывает 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/stable/advanced_topics/amp.html