Spec-Zone.ru › Wagtail 2

Как создать сайт с поддержкой AMP

В этом документе описывается метод создания версии сайта Wagtail с поддержкой AMP и размещения ее отдельно от остальной части сайта по префиксу URL. Также описывается, как заставить Wagtail отображать изображения с тегом <amp-img> при посещении страницы AMP-версии сайта пользователем.

Обзор

В следующем разделе мы добавим новую запись URL, которая указывает на внутренний serve() вид Wagtail, что приведет к повторному отображению всего сайта по префиксу /amp.

Затем мы добавим некоторые утилиты, которые позволят отслеживать, находится ли текущий запрос в префиксной версии сайта /amp без необходимости объекта запроса.

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

И наконец, мы изменим поведение тега {% image %}, чтобы при отрисовке AMP-версии сайта он отображал теги <amp-img>.

Создание второго дерева страниц

Мы можем отображать весь сайт по другому префиксу, дублируя 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, который использовался для отображения страницы. Для этого нам нужно обернуть 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 — это менеджер контекста, который можно вызвать с помощью синтаксиса Python with. В теле оператора with режим AMP будет активным.
  • amp_mode_active — это функция, которая возвращает True когда активен режим AMP.

Далее, нам нужно определить вид, который оборачивает встроенный serve вид Wagtail и вызывает менеджер контекста activate_amp_mode.

# <app>/amp_views.py

from django.template.response import SimpleTemplateResponse
from wagtail.core.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.core.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'

Переопределение тега изображения для вывода тегов amp-img

Наконец, давайте изменим тег изображения Wagtail, чтобы он отображал теги <amp-img> при отображении страниц с включенным AMP. Мы внесем изменения в модель Rendition, чтобы это применилось как к изображениям, отображаемым с помощью тега {% image %}, так и к изображениям, отображаемым в полях богатого текста.

С собственной моделью изображений это проще, поскольку вы можете переопределить метод img_tag в своей собственной модели Rendition для возврата другого тега.

Например:

from django.forms.utils import flatatt
from django.utils.safestring import mark_safe

from wagtail.images.models import AbstractRendition

...

class CustomRendition(AbstractRendition):
    def img_tag(self, extra_attributes):
        attrs = self.attrs_dict.copy()
        attrs.update(extra_attributes)

        if amp_mode_active():
            return mark_safe('<amp-img{}>'.format(flatatt(attrs)))
        else:
            return mark_safe('<img{}>'.format(flatatt(attrs)))

    ...

Без кастомной модели изображений вам придется заменить встроенную модель Rendition. Добавьте это в любой части вашего проекта, где она импортируется при запуске:

from django.forms.utils import flatatt
from django.utils.safestring import mark_safe

from wagtail.images.models import Rendition

def img_tag(rendition, extra_attributes={}):
    """
    Replacement implementation for Rendition.img_tag

    When AMP mode is on, this returns an <amp-img> tag instead of an <img> tag
    """
    attrs = rendition.attrs_dict.copy()
    attrs.update(extra_attributes)

    if amp_mode_active():
        return mark_safe('<amp-img{}>'.format(flatatt(attrs)))
    else:
        return mark_safe('<img{}>'.format(flatatt(attrs)))

Rendition.img_tag = img_tag
  • Предыдущая Руководство по использованию API Wagtail v2
  • Следующая Соображения по обеспечению доступности

Содержание страницы

  • Как создать сайт с поддержкой AMP
    • Обзор
    • Создание второго дерева страниц
    • Информирование страниц о режиме «AMP»
    • Напишите обработчик контекста шаблона, чтобы состояние AMP можно было проверить в шаблонах
    • Использование другого шаблона страницы, когда активен режим AMP
    • Переопределение тега изображения для вывода тегов amp-img

© 2014-present Torchbox Ltd and individual contributors.
All rights are reserved.
Licensed under the BSD License.
https://docs.wagtail.org/en/v2.16.3/advanced_topics/amp.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API