Spec-Zone.ru › Wagtail 3

Гаксы

При загрузке Wagtail будет искать любой приложение с файлом wagtail_hooks.py и выполнять его содержимое. Это предоставляет способ зарегистрировать собственные функции для выполнения в определённые моменты выполнения Wagtail, такие как сохранение страницы или построение основного меню.

Примечание

Гаксы обычно используются для настройки поведения на уровне представления в админ-панели Wagtail и на фронтенде. Для настроек, которые затрагивают только поведение на уровне модели, например, вызов внешнего сервиса при добавлении страницы или документа, лучше использовать механизм сигналов Django механизм сигналов Django (см. также: Сигналы Wagtail), так как они не зависят от конкретного пути пользователя через админ-интерфейс.

Регистрация функций с помощью гака Wagtail выполняется с помощью декоратора @hooks.register.

from wagtail import hooks

@hooks.register('name_of_hook')
def my_hook_function(arg1, arg2...)
    # your code here

В качестве альтернативы, можно вызвать hooks.register как обычную функцию, передав имя гака и функцию-обработчик, определённую в другом месте:

hooks.register('name_of_hook', my_hook_function)

Если вам необходимо, чтобы ваши гаки выполнялись в определённом порядке, можно передать параметр order. Если порядок не указан, гаки выполняются в порядке, заданном в INSTALLED_APPS. Wagtail также использует гаки внутри, поэтому вам нужно учитывать порядок при переопределении встроенных функций Wagtail (например, удаление стандартных элементов резюме):

@hooks.register('name_of_hook', order=1)  # This will run after every hook in the wagtail core
def my_hook_function(arg1, arg2...)
    # your code here

@hooks.register('name_of_hook', order=-1)  # This will run before every hook in the wagtail core
def my_other_hook_function(arg1, arg2...)
    # your code here

@hooks.register('name_of_hook', order=2)  # This will run after `my_hook_function`
def yet_another_hook_function(arg1, arg2...)
    # your code here

Тестирование гаков в среде разработки

Гаксы обычно регистрируются при запуске и не могут быть изменены во время выполнения. Но при написании юнит-тестов вы можете захотеть зарегистрировать функцию-гак только для одного теста или блока кода и отменить её регистрацию, чтобы она не выполнялась при запуске других тестов.

Вы можете временно зарегистрировать гаки, используя функцию hooks.register_temporarily, её можно использовать как декоратор, так и менеджер контекста. Вот пример того, как зарегистрировать функцию-гак только для одного теста:

def my_hook_function():
    ...

class MyHookTest(TestCase):

    @hooks.register_temporarily('name_of_hook', my_hook_function)
    def test_my_hook_function(self):
        # Test with the hook registered here
        ...

И вот пример регистрации функции-гака для одного блока кода:

def my_hook_function():
    ...

with hooks.register_temporarily('name_of_hook', my_hook_function):
    # Hook is registered here
    ..

# Hook is unregistered here

Если вам нужно зарегистрировать несколько гаков в блоке with, вы можете передать их в виде списка кортежей:

def my_hook(...):
    pass

def my_other_hook(...):
    pass

with hooks.register_temporarily([
    ('hook_name', my_hook),
    ('hook_name', my_other_hook),
]):
    # All hooks are registered here
    ..

# All hooks are unregistered here

Доступные гаки перечислены ниже.

Модули админ-панели

Гаксы для создания новых областей в админ-интерфейсе (наряду со страницами, изображениями, документами и т. д.).

construct_homepage_panels

Добавление или удаление панелей с домашней страницы админ-панели Wagtail. Передаваемая в этот гак функция должна принимать объект request и список объектов панелей и должна изменять этот список по мере необходимости. Объекты панелей — это компоненты с дополнительным свойством order, целым числом, которое определяет позицию панели в окончательном отсортированном списке. Стандартные панели используют целые числа от 100 до 300.

from django.utils.safestring import mark_safe

from wagtail.admin.ui.components import Component
from wagtail import hooks

class WelcomePanel(Component):
    order = 50

    def render_html(self, parent_context):
        return mark_safe("""
        <section class="panel summary nice-padding">
          <h3>No, but seriously -- welcome to the admin homepage.</h3>
        </section>
        """)

@hooks.register('construct_homepage_panels')
def add_another_welcome_panel(request, panels):
    panels.append(WelcomePanel())

construct_homepage_summary_items

Добавление или удаление элементов из панели «Краткое описание сайта» на главной странице админ-панели (которая отображает количество страниц и других объектов, существующих на сайте). Передаваемая в этот гак функция должна принимать объект request и список объектов элементов краткого описания и должна изменять этот список по мере необходимости. Объекты элементов краткого описания — экземпляры wagtail.admin.site_summary.SummaryItem, которые расширяют класс Component с добавлением следующих дополнительных методов и свойств:

construct_main_menu

Вызывается непосредственно перед выводом меню админ-панели Wagtail, чтобы разрешить изменение списка элементов меню. Передаваемая в этот гак функция получит объект request и список menu_items, и должна изменить menu_items по мере необходимости. Добавление элементов меню, как правило, выполняется с помощью гака register_admin_menu_item вместо этого — элементы, добавленные через construct_main_menu, не будут проверены на is_shown.

from wagtail import hooks

@hooks.register('construct_main_menu')
def hide_explorer_menu_item_from_frank(request, menu_items):
  if request.user.username == 'frank':
    menu_items[:] = [item for item in menu_items if item.name != 'explorer']

describe_collection_contents

Вызывается, когда Wagtail нужно узнать, какие объекты существуют в коллекции, если таковые есть. В настоящее время это происходит при подтверждении перед удалением коллекции, чтобы убедиться, что пустые коллекции не могут быть удалены. Передаваемая в этот гак функция получит объект collection и должна вернуть либо None (чтобы указать отсутствие объектов в этой коллекции), либо словарь, содержащий следующие ключи:

register_account_settings_panel

Регистрирует новый класс панели настроек для добавления в представление «Аккаунт» в админ-панели.

Этот гак может быть добавлен в подкласс BaseSettingsPanel. Например:

from wagtail.admin.views.account import BaseSettingsPanel
from wagtail import hooks

@hooks.register('register_account_settings_panel')
class CustomSettingsPanel(BaseSettingsPanel):
    name = 'custom'
    title = "My custom settings"
    order = 500
    form_class = CustomSettingsForm

В качестве альтернативы, он также может быть добавлен в функцию. Например, эта функция эквивалентна вышеприведённой:

from wagtail.admin.views.account import BaseSettingsPanel
from wagtail import hooks

class CustomSettingsPanel(BaseSettingsPanel):
    name = 'custom'
    title = "My custom settings"
    order = 500
    form_class = CustomSettingsForm

@hooks.register('register_account_settings_panel')
def register_custom_settings_panel(request, user, profile):
    return CustomSettingsPanel(request, user, profile)

Более подробную информацию о доступных параметрах можно найти в Настройка формы настроек пользовательского аккаунта.

register_account_menu_item

Добавляет элемент на вкладку «Дополнительные действия» на странице «Аккаунт» в админ-панели Wagtail. Функция-обработчик для этого гака должна вернуть словарь с ключами url, label и help_text. Например:

from django.urls import reverse
from wagtail import hooks

@hooks.register('register_account_menu_item')
def register_account_delete_account(request):
    return {
        'url': reverse('delete-account'),
        'label': 'Delete account',
        'help_text': 'This permanently deletes your account.'
    }

register_admin_menu_item

Добавление элемента в меню админ-панели Wagtail. Передаваемая в этот гак функция должна вернуть экземпляр wagtail.admin.menu.MenuItem. Новые элементы можно создать из класса MenuItem, передав label, что будет текстом в элементе меню, и URL-адрес страницы админ-панели, к которой вы хотите связать элемент меню (обычно, вызывая reverse() в админ-представлении, которое вы настроили). Кроме того, принимаются следующие ключевые аргументы:

Для элементов меню, доступных только суперпользователям, можно использовать подкласс wagtail.admin.menu.AdminOnlyMenuItem вместо MenuItem.

MenuItem можно дополнительно наследовать, чтобы настроить его инициализацию или условно отображать или скрывать элемент для определённых запросов (например, для применения проверок разрешений); подробности см. в исходном коде (wagtail/admin/menu.py).

from django.urls import reverse

from wagtail import hooks
from wagtail.admin.menu import MenuItem

@hooks.register('register_admin_menu_item')
def register_frank_menu_item():
  return MenuItem('Frank', reverse('frank'), icon_name='folder-inverse', order=10000)

register_admin_urls

Регистрация дополнительных URL-адресов страниц админ-панели. Передаваемая в этот гак функция должна вернуть список шаблонов URL Django, которые определяют структуру страниц и точек входа вашего расширения для админ-панели Wagtail. Подробнее о стандартных Django URLconfs и представлениях см. диспетчер URL.

from django.http import HttpResponse
from django.urls import path

from wagtail import hooks

def admin_view(request):
  return HttpResponse(
    "I have approximate knowledge of many things!",
    content_type="text/plain")

@hooks.register('register_admin_urls')
def urlconf_time():
  return [
    path('how_did_you_almost_know_my_name/', admin_view, name='frank'),
  ]

register_group_permission_panel

Добавление новой панели к форме групп в области «Настройки». Передаваемая в этот гак функция должна вернуть класс ModelForm/ModelFormSet, с конструктором, который принимает объект группы в качестве ключевого аргумента instance, и который реализует методы save, is_valid, и as_admin_panel (который возвращает HTML, который необходимо включить на странице редактирования группы).

register_settings_menu_item

Как register_admin_menu_item, но регистрирует элементы меню в подменю «Настройки», а не в главном меню.

construct_settings_menu

Как construct_main_menu, но изменяет подменю «Настройки», а не главное меню.

register_reports_menu_item

Как register_admin_menu_item, но регистрирует элементы меню в подменю «Отчёты», а не в главном меню.

construct_reports_menu

Как construct_main_menu, но изменяет подменю «Отчёты», а не главное меню.

register_admin_search_area

Добавление элемента в поиск Wagtail-админ-панели «Другие поиски». Поведение этого гака аналогично register_admin_menu_item. Передаваемая в этот гак функция должна вернуть экземпляр wagtail.admin.search.SearchArea. Новые элементы можно создать из класса SearchArea, передав следующие параметры:

Установка URL-адреса может быть достигнута с помощью reverse() на целевой странице поиска. Параметр GET «q» будет добавлен к данному URL-адресу.

Тэг шаблона search_other предоставляется модулем шаблонов wagtailadmin_tags. Этот тег принимает один необязательный параметр current, который позволяет указать name активного параметра поиска. Если параметр не задан, гак по умолчанию выполняет обратный поиск URL-адреса страницы для сравнения с параметром url.

SearchArea может быть расширен для настройки вывода HTML, указания необходимых JavaScript-файлов или условного отображения/скрытия элемента для определённых запросов (например, для применения проверок разрешений); подробности см. в исходном коде (wagtail/admin/search.py).

from django.urls import reverse
from wagtail import hooks
from wagtail.admin.search import SearchArea

@hooks.register('register_admin_search_area')
def register_frank_search_area():
    return SearchArea('Frank', reverse('frank'), icon_name='folder-inverse', order=10000)

register_permissions

Возвращает QuerySet объектов Permission для отображения в области администрирования групп.

from django.contrib.auth.models import Permission
from wagtail import hooks


@hooks.register('register_permissions')
def register_permissions():
    app = 'blog'
    model = 'extramodelset'

    return Permission.objects.filter(content_type__app_label=app, codename__in=[
        f"view_{model}", f"add_{model}", f"change_{model}", f"delete_{model}"
    ])

filter_form_submissions_for_user

Разрешает настройку доступа к отправленным формам на основе пользователя и формы.

Гак должен вернуть QuerySet, содержащий подмножество этих страниц форм, к которым пользователь имеет разрешение для доступа.

Например, чтобы предотвратить доступ к отправкам форм для не-суперпользователей:

from wagtail import hooks


@hooks.register('filter_form_submissions_for_user')
def construct_forms_for_user(user, queryset):
    if not user.is_superuser:
        queryset = queryset.none()

    return queryset

Интерфейс редактора

Фиксаторы для настройки интерфейса редактирования страниц и фрагментов.

register_rich_text_features

Поля rich text в Wagtail работают со списком идентификаторов «функций», которые определяют, какие элементы управления редактированием доступны в редакторе, и какие элементы разрешены в выводе; например, поле rich text, определённое как RichTextField(features=['h2', 'h3', 'bold', 'italic', 'link']) , будет допускать заголовки, форматирование полужирным/курсивом и ссылки, но не (например) маркированные списки или изображения. Фиксатор register_rich_text_features позволяет определять новые идентификаторы функций — см. Ограничение функций в поле rich text для получения подробностей.

insert_editor_css

Добавить дополнительные файлы CSS или фрагменты в редактор страницы.

from django.templatetags.static import static
from django.utils.html import format_html

from wagtail import hooks

@hooks.register('insert_editor_css')
def editor_css():
    return format_html(
        '<link rel="stylesheet" href="{}">',
        static('demo/css/vendor/font-awesome/css/font-awesome.min.css')
    )

insert_global_admin_css

Добавить дополнительные файлы CSS или фрагменты на все страницы админки.

from django.utils.html import format_html
from django.templatetags.static import static

from wagtail import hooks

@hooks.register('insert_global_admin_css')
def global_admin_css():
    return format_html('<link rel="stylesheet" href="{}">', static('my/wagtail/theme.css'))

insert_editor_js

Добавить дополнительные файлы JavaScript или фрагменты кода в редактор страницы.

from django.utils.html import format_html_join
from django.utils.safestring import mark_safe
from django.templatetags.static import static

from wagtail import hooks

@hooks.register('insert_editor_js')
def editor_js():
    js_files = [
        'js/fireworks.js', # https://fireworks.js.org
    ]
    js_includes = format_html_join('\n', '<script src="{0}"></script>',
        ((static(filename),) for filename in js_files)
    )
    return js_includes + mark_safe(
        """
        <script>
            window.addEventListener('DOMContentLoaded', (event) => {
                var container = document.createElement('div');
                container.style.cssText = 'position: fixed; width: 100%; height: 100%; z-index: 100; top: 0; left: 0; pointer-events: none;';
                container.id = 'fireworks';
                document.getElementById('main').prepend(container);
                var options = { "acceleration": 1.2, "autoresize": true, "mouse": { "click": true, "max": 3 } };
                var fireworks = new Fireworks(document.getElementById('fireworks'), options);
                fireworks.start();
            });
        </script>
        """
    )

insert_global_admin_js

Добавить дополнительные файлы JavaScript или фрагменты кода на все страницы админки.

from django.utils.safestring import mark_safe

from wagtail import hooks

@hooks.register('insert_global_admin_js')
def global_admin_js():
    return mark_safe(
        '<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r74/three.js"></script>',
    )

register_page_header_buttons

Добавить кнопки в дополнительное выпадающее меню в представлении редактирования страницы. Это работает аналогично фиксатору register_page_listing_buttons.

Этот пример добавит простую кнопку в дополнительное выпадающее меню:

from wagtail.admin import widgets as wagtailadmin_widgets

@hooks.register('register_page_header_buttons')
def page_header_buttons(page, page_perms, next_url=None):
    yield wagtailadmin_widgets.Button(
        'A dropdown button',
        '/goes/to/a/url/',
        priority=60
    )

Аргументы, передаваемые в фиксатор, следующие:

  • page — объект страницы для создания кнопки
  • page_perms — объект PagePermissionTester, который можно запросить, чтобы определить разрешения текущего пользователя на данной странице
  • next_url — URL, к которому должна перенаправляться связанная операция по завершении действия, если представление это поддерживает

Аргумент priority управляет порядком отображения кнопок в выпадающем меню. Кнопки упорядочены по приоритету от низкого к высокому, поэтому кнопка с priority=10 будет отображаться перед кнопкой с priority=60.

Рабочий процесс редактора

Крючки для настройки способа, которым пользователи проходят процесс создания контента страницы.

after_create_page

Выполните какие-либо действия с объектом Page после того, как он был сохранён в базе данных (как опубликованная страница или ревизия). Переданный в этот крючок вызываемый объект должен принять объект request и объект page. Функция не обязана возвращать ничего, но если возвращается объект с свойством status_code, Wagtail воспользуется им как объектом ответа. По умолчанию Wagtail перенаправляет на страницу Обозревателя для родительской страницы новой страницы.

from django.http import HttpResponse

from wagtail import hooks

@hooks.register('after_create_page')
def do_after_page_create(request, page):
    return HttpResponse("Congrats on making content!", content_type="text/plain")

Если вы установили атрибуты на объекте Page, вы также должны вызвать save_revision(), так как представление редактирования и представление индекса получают свои данные из таблицы ревизий, а не из фактического сохранённого записей страницы.

@hooks.register('after_create_page')
def set_attribute_after_page_create(request, page):
   page.title = 'Persistent Title'
   new_revision = page.save_revision()
   if page.live:
       # page has been created and published at the same time,
       # so ensure that the updated title is on the published version too
       new_revision.publish()

before_create_page

Вызывается в начале представления «создание страницы», передавая запрос, родительскую страницу и класс модели страницы.

Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа и пропустит остальную часть представления.

В отличие от after_create_page, это выполняется как для запросов GET, так и для запросов POST.

Это можно использовать для полной замены редактора на основе представления:

from wagtail import hooks

from .models import AwesomePage
from .admin_views import edit_awesome_page

@hooks.register('before_create_page')
def before_create_page(request, parent_page, page_class):
    # Use a custom create view for the AwesomePage model
    if page_class == AwesomePage:
        return create_awesome_page(request, parent_page)

after_delete_page

Выполните какие-либо действия после удаления объекта Page. Используется тот же механизм, что и в after_create_page.

before_delete_page

Вызывается в начале представления «удаление страницы», передавая запрос и объект страницы.

Используется тот же механизм, что и в before_create_page, выполняется как для запросов GET, так и для запросов POST.

from django.shortcuts import redirect
from django.utils.html import format_html

from wagtail.admin import messages
from wagtail import hooks

from .models import AwesomePage


@hooks.register('before_delete_page')
def before_delete_page(request, page):
    """Block awesome page deletion and show a message."""

    if request.method == 'POST' and page.specific_class in [AwesomePage]:
        messages.warning(request, "Awesome pages cannot be deleted, only unpublished")
        return redirect('wagtailadmin_pages:delete', page.pk)

after_edit_page

Выполните какие-либо действия с объектом Page после его обновления. Используется тот же механизм, что и в after_create_page.

before_edit_page

Вызывается в начале представления «редактирование страницы», передавая запрос и объект страницы.

Используется тот же механизм, что и в before_create_page.

after_publish_page

Выполните какие-либо действия с объектом Page после его публикации через представление создания страницы или представления редактирования страницы.

Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа и пропустит остальную часть представления.

before_publish_page

Выполните какие-либо действия с объектом Page перед его публикацией через представление создания страницы или представление редактирования страницы.

Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа и пропустит остальную часть представления.

after_unpublish_page

Вызывается после действия «снятие с публикации» в представлении «снятие с публикации», передавая запрос и объект страницы.

Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа и пропустит остальную часть представления.

before_unpublish_page

Вызывается перед действием «снятие с публикации» в представлении «снятие с публикации», передавая запрос и объект страницы.

Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа и пропустит остальную часть представления.

after_copy_page

Выполните какие-либо действия с объектом Page после его копирования, передавая запрос, объект страницы и новую скопированную страницу. Используется тот же механизм, что и в after_create_page.

before_copy_page

Вызывается в начале представления «копирование страницы», передавая запрос и объект страницы.

Используется тот же механизм, что и в before_create_page.

after_move_page

Выполните какие-либо действия с объектом Page после его перемещения, передавая запрос и объект страницы. Используется тот же механизм, что и в after_create_page.

before_move_page

Вызывается в начале представления «перемещение страницы», передавая запрос, объект страницы и целевой объект страницы.

Используется тот же механизм, что и в before_create_page.

before_convert_alias_page

Вызывается в начале представления convert_alias, которое отвечает за преобразование страниц-псевдонимов в обычные страницы Wagtail.

Запрос и преобразуемая страница передаются в качестве аргументов крючку.

Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа и пропустит остальную часть представления.

after_convert_alias_page

Выполните какие-либо действия с объектом Page после его преобразования из псевдонима.

Запрос и только что преобразованная страница передаются в качестве аргументов крючку.

Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа и пропустит остальную часть представления.

register_page_action_menu_item

Добавьте элемент в всплывающее меню действий на страницах создания и редактирования. Вызываемый объект, переданный в этот крючок, должен вернуть экземпляр wagtail.admin.action_menu.ActionMenuItem. wagtail.admin.action_menu.ActionMenuItem является подклассом Компонента, и поэтому отображение элемента меню может быть настроено с помощью template_name, get_context_data, render_html и Media.

Кроме того, доступны следующие атрибуты и методы для переопределения:

Методы get_url, is_shown, get_context_data и render_html принимают словарь контекста, содержащий следующие поля:

from wagtail import hooks
from wagtail.admin.action_menu import ActionMenuItem

class GuacamoleMenuItem(ActionMenuItem):
    name = 'action-guacamole'
    label = "Guacamole"

    def get_url(self, context):
        return "https://www.youtube.com/watch?v=dNJdJIwCF_Y"


@hooks.register('register_page_action_menu_item')
def register_guacamole_menu_item():
    return GuacamoleMenuItem(order=10)

construct_page_action_menu

Измените конечный список элементов меню действий на страницах создания и редактирования. Переданный в этот крючок вызываемый объект получает список объектов ActionMenuItem, объект запроса и словарь контекста, как в register_page_action_menu_item, и должен изменить список элементов меню на месте.

@hooks.register('construct_page_action_menu')
def remove_submit_to_moderator_option(menu_items, request, context):
    menu_items[:] = [item for item in menu_items if item.name != 'action-submit']

Крючок construct_page_action_menu вызывается после того, как элементы меню были отсортированы по их атрибутам порядка, поэтому установка порядка элемента меню не повлияет на этот момент. Вместо этого элементы можно переупорядочить, изменив их положение в списке, при этом первый элемент будет выбран как действие по умолчанию. Например, чтобы изменить действие по умолчанию на «Опубликовать»:

@hooks.register('construct_page_action_menu')
def make_publish_default_action(menu_items, request, context):
    for (index, item) in enumerate(menu_items):
        if item.name == 'action-publish':
            # move to top of list
            menu_items.pop(index)
            menu_items.insert(0, item)
            break

construct_page_listing_buttons

Измените конечный список кнопок отображения страницы в обозревателе страниц. Вызываемый объект, переданный в этот крючок, получает список объектов PageListingButton, страницу, объект разрешений страницы и словарь контекста, как в register_page_listing_buttons, и должен изменить список элементов отображения на месте.

@hooks.register('construct_page_listing_buttons')
def remove_page_listing_button_item(buttons, page, page_perms, is_parent=False, context=None):
    if is_parent:
        buttons.pop() # removes the last 'more' dropdown button on the parent page listing buttons

construct_wagtail_userbar

Добавить или удалить элементы из панели инструментов Wagtail. По умолчанию предоставляются инструменты добавления, редактирования и модерации. Вызываемый объект, переданный в крючок, должен принять объект request и список объектов меню items. Объекты элементов меню должны иметь метод render, который может принять объект request и вернуть строку HTML, представляющую элемент меню. Дополнительная информация находится в шаблонах панели инструментов и классах элементов меню.

from wagtail import hooks

class UserbarPuppyLinkItem:
    def render(self, request):
        return '<li><a href="http://cuteoverload.com/tag/puppehs/" ' \
            + 'target="_parent" role="menuitem" class="action icon icon-wagtail">Puppies!</a></li>'

@hooks.register('construct_wagtail_userbar')
def add_puppy_link_item(request, items):
    return items.append( UserbarPuppyLinkItem() )

Рабочий процесс администратора

Крючки для настройки способа, которым администраторы проходят процесс редактирования пользователей.

after_create_user

Выполните какие-либо действия с объектом User после его сохранения в базе данных. Вызываемый объект, переданный в этот крючок, должен принять объект request и объект user. Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа. По умолчанию Wagtail перенаправляет на страницу индекса пользователей.

from django.http import HttpResponse

from wagtail import hooks

@hooks.register('after_create_user')
def do_after_page_create(request, user):
    return HttpResponse("Congrats on creating a new user!", content_type="text/plain")

before_create_user

Вызывается в начале представления «создание пользователя», передавая запрос.

Функция не обязана возвращать ничего, но если возвращается объект со свойством status_code, Wagtail воспользуется им как объектом ответа и пропустит остальную часть представления.

В отличие от after_create_user, это выполняется как для запросов GET, так и для запросов POST.

Это можно использовать для полной замены редактора пользователя на основе представления:

from django.http import HttpResponse

from wagtail import hooks

from .models import AwesomePage
from .admin_views import edit_awesome_page

@hooks.register('before_create_user')
def before_create_page(request):
    return HttpResponse("A user creation form", content_type="text/plain")

after_delete_user

Выполните какие-либо действия после удаления объекта User. Используется тот же механизм, что и в after_create_user.

before_delete_user

Вызывается в начале представления «удаление пользователя», передавая запрос и объект пользователя.

Используется тот же механизм, что и в before_create_user.

after_edit_user

Выполните какие-либо действия с объектом User после его обновления. Используется тот же механизм, что и в after_create_user.

before_edit_user

Вызывается в начале представления «редактирование пользователя», передавая запрос и объект пользователя.

Используется тот же механизм, что и в before_create_user.

END_OF_DOCUMENT_MARKER

Выбиратели

construct_page_chooser_queryset

Вызывается при отображении представления выбора страницы, чтобы позволить настроить запрос QuerySet для списка страниц. Передаваемая в обработчик функция получит текущий запрос QuerySet страницы и объект запроса, и должна вернуть запрос QuerySet страницы (либо исходный, либо новый).

from wagtail import hooks

@hooks.register('construct_page_chooser_queryset')
def show_my_pages_only(pages, request):
    # Only show own pages
    pages = pages.filter(owner=request.user)

    return pages

construct_document_chooser_queryset

Вызывается при отображении представления выбора документа, чтобы позволить настроить запрос QuerySet для списка документов. Передаваемая в обработчик функция получит текущий запрос QuerySet документа и объект запроса, и должна вернуть запрос QuerySet документа (либо исходный, либо новый).

from wagtail import hooks

@hooks.register('construct_document_chooser_queryset')
def show_my_uploaded_documents_only(documents, request):
    # Only show uploaded documents
    documents = documents.filter(uploaded_by_user=request.user)

    return documents

construct_image_chooser_queryset

Вызывается при отображении представления выбора изображения, чтобы позволить настроить запрос QuerySet для списка изображений. Передаваемая в обработчик функция получит текущий запрос QuerySet изображения и объект запроса, и должна вернуть запрос QuerySet изображения (либо исходный, либо новый).

from wagtail import hooks

@hooks.register('construct_image_chooser_queryset')
def show_my_uploaded_images_only(images, request):
    # Only show uploaded images
    images = images.filter(uploaded_by_user=request.user)

    return images

Обзор страниц

construct_explorer_page_queryset

Вызывается при отображении представления обзора страниц, чтобы позволить настроить запрос QuerySet для списка страниц. Передаваемая в обработчик функция получит родительский объект страницы, текущий запрос QuerySet страницы и объект запроса, и должна вернуть запрос QuerySet страницы (либо исходный, либо новый).

from wagtail import hooks

@hooks.register('construct_explorer_page_queryset')
def show_my_profile_only(parent_page, pages, request):
    # If we're in the 'user-profiles' section, only show the user's own profile
    if parent_page.slug == 'user-profiles':
        pages = pages.filter(owner=request.user)

    return pages

register_page_listing_buttons

Добавляет кнопки в список действий для страницы в окне обзора страниц. Это полезно при добавлении пользовательских действий в список, таких как переводы или сложный рабочий процесс.

Этот пример добавит простую кнопку в список:

from wagtail.admin import widgets as wagtailadmin_widgets

@hooks.register('register_page_listing_buttons')
def page_listing_buttons(page, page_perms, is_parent=False, next_url=None):
    yield wagtailadmin_widgets.PageListingButton(
        'A page listing button',
        '/goes/to/a/url/',
        priority=10
    )

Аргументы, передаваемые в обработчик, следующие:

  • page — объект страницы, для которой должна быть сгенерирована кнопка
  • page_perms — объект, который можно запросить, чтобы определить разрешения текущего пользователя на данной странице
  • is_parent — если true, эта кнопка отображается для родительской страницы, отображаемой вверху списка
  • next_url — URL, на который должна перенаправить связанное действие при завершении действия, если представление его поддерживает

Аргумент priority управляет порядком отображения кнопок. Кнопки упорядочены от низкого к высокому приоритету, поэтому кнопка с priority=10 будет отображаться перед кнопкой с priority=20.

register_page_listing_more_buttons

Добавляет кнопки в раскрывающееся меню «Ещё» для страницы в окне обзора страниц. Это работает аналогично обработчику register_page_listing_buttons, но полезно для менее используемых пользовательских действий, которые лучше подходят для раскрывающегося меню.

Этот пример добавит простую кнопку в раскрывающееся меню:

from wagtail.admin import widgets as wagtailadmin_widgets

@hooks.register('register_page_listing_more_buttons')
def page_listing_more_buttons(page, page_perms, is_parent=False, next_url=None):
    yield wagtailadmin_widgets.Button(
        'A dropdown button',
        '/goes/to/a/url/',
        priority=60
    )

Аргументы, передаваемые в обработчик, следующие:

  • page — объект страницы, для которой должна быть сгенерирована кнопка
  • page_perms — объект, который можно запросить, чтобы определить разрешения текущего пользователя на данной странице
  • is_parent — если true, эта кнопка отображается для родительской страницы, отображаемой вверху списка
  • next_url — URL, на который должна перенаправить связанное действие при завершении действия, если представление его поддерживает

Аргумент priority управляет порядком отображения кнопок в раскрывающемся меню. Кнопки упорядочены от низкого к высокому приоритету, поэтому кнопка с priority=10 будет отображаться перед кнопкой с priority=60.

Кнопки с раскрывающимися списками

Виджеты администратора также предоставляют ButtonWithDropdownFromHook, что позволяет определить пользовательский обработчик для генерации раскрывающегося меню, которое прикрепляется к вашей кнопке.

Создание кнопки с раскрывающимся меню включает два шага. Во-первых, вы добавляете свою кнопку к обработчику register_page_listing_buttons, как в примере выше. Во-вторых, вы регистрируете новый обработчик, который возвращает содержимое раскрывающегося меню.

Этот пример показывает, как реализовано стандартное раскрывающееся меню администратора Wagtail. Вы также можете увидеть, как регистрировать кнопки условно, в данном случае путём оценки page_perms:

from wagtail.admin import widgets as wagtailadmin_widgets

@hooks.register('register_page_listing_buttons')
def page_custom_listing_buttons(page, page_perms, is_parent=False, next_url=None):
    yield wagtailadmin_widgets.ButtonWithDropdownFromHook(
        'More actions',
        hook_name='my_button_dropdown_hook',
        page=page,
        page_perms=page_perms,
        is_parent=is_parent,
        next_url=next_url,
        priority=50
    )

@hooks.register('my_button_dropdown_hook')
def page_custom_listing_more_buttons(page, page_perms, is_parent=False, next_url=None):
    if page_perms.can_move():
        yield wagtailadmin_widgets.Button('Move', reverse('wagtailadmin_pages:move', args=[page.id]), priority=10)
    if page_perms.can_delete():
        yield wagtailadmin_widgets.Button('Delete', reverse('wagtailadmin_pages:delete', args=[page.id]), priority=30)
    if page_perms.can_unpublish():
        yield wagtailadmin_widgets.Button('Unpublish', reverse('wagtailadmin_pages:unpublish', args=[page.id]), priority=40)

Шаблон кнопки раскрывающегося меню можно настроить, переопределив wagtailadmin/pages/listing/_button_with_dropdown.html. JavaScript, который управляет раскрывающимися меню, использует пользовательские атрибуты данных, поэтому вы должны оставить data-dropdown и data-dropdown-toggle в разметке, если вы её настраиваете.

Обслуживание страницы

before_serve_page

Вызывается, когда Wagtail собирается обслуживать страницу. Передаваемая в обработчик функция получит объект страницы, объект запроса и args и kwargs, которые будут переданы в метод serve() страницы. Если обработчик возвращает HttpResponse, этот ответ будет немедленно возвращен пользователю, и Wagtail не будет вызывать serve() на странице.

from django.http import HttpResponse

from wagtail import hooks

@hooks.register('before_serve_page')
def block_googlebot(page, request, serve_args, serve_kwargs):
    if request.META.get('HTTP_USER_AGENT') == 'GoogleBot':
        return HttpResponse("<h1>bad googlebot no cookie</h1>")

Обслуживание документа

before_serve_document

Вызывается, когда Wagtail собирается обслуживать документ. Передаваемая в обработчик функция получит объект документа и объект запроса. Если обработчик возвращает HttpResponse, этот ответ будет немедленно возвращен пользователю вместо обслуживания документа. Обратите внимание, что этот обработчик будет пропущен, если значение настройки WAGTAILDOCS_SERVE_METHOD установлено в direct.

Сниппеты

Вспомогательные функции для работы с зарегистрированными Сниппетами.

after_edit_snippet

Вызывается при редактировании Сниппета. Переданная в хук функция получит экземпляр модели и объект запроса. Если функция вернёт HttpResponse, этот ответ будет сразу возвращён пользователю, и Wagtail не будет вызывать redirect() для просмотра списка.

from django.http import HttpResponse

from wagtail import hooks

@hooks.register('after_edit_snippet')
def after_snippet_update(request, instance):
    return HttpResponse(f"Congrats on editing a snippet with id {instance.pk}", content_type="text/plain")

before_edit_snippet

Вызывается в начале просмотра страницы редактирования сниппета. Переданная в хук функция получит экземпляр модели и объект запроса. Если функция вернёт HttpResponse, этот ответ будет сразу возвращён пользователю, и Wagtail не будет вызывать redirect() для просмотра списка.

from django.http import HttpResponse

from wagtail import hooks

@hooks.register('before_edit_snippet')
def block_snippet_edit(request, instance):
    if isinstance(instance, RestrictedSnippet) and instance.prevent_edit:
        return HttpResponse("Sorry, you can't edit this snippet", content_type="text/plain")

after_create_snippet

Вызывается при создании Сниппета. after_create_snippet и after_edit_snippet работают одинаково. Единственное отличие — место вызова хука.

before_create_snippet

Вызывается в начале просмотра страницы создания сниппета. Работает аналогично before_edit_snippet, за исключением того, что модель передаётся в качестве аргумента вместо экземпляра.

after_delete_snippet

Вызывается при удалении Сниппета. Переданная в хук функция получит набор экземпляров модели (как объект QuerySet) и объект запроса. Если функция вернёт HttpResponse, этот ответ будет сразу возвращён пользователю, и Wagtail не будет вызывать redirect() для просмотра списка.

from django.http import HttpResponse

from wagtail import hooks

@hooks.register('after_delete_snippet')
def after_snippet_delete(request, instances):
    # "instances" is a QuerySet
    total = len(instances)
    return HttpResponse(f"{total} snippets have been deleted", content_type="text/plain")

before_delete_snippet

Вызывается в начале просмотра страницы удаления сниппета. Переданная в хук функция получит набор экземпляров модели (как объект QuerySet) и объект запроса. Если функция вернёт HttpResponse, этот ответ будет сразу возвращён пользователю, и Wagtail не будет вызывать redirect() для просмотра списка.

from django.http import HttpResponse

from wagtail import hooks

@hooks.register('before_delete_snippet')
def before_snippet_delete(request, instances):
    # "instances" is a QuerySet
    total = len(instances)

    if request.method == 'POST':
      # Override the deletion behaviour
      instances.delete()

      return HttpResponse(f"{total} snippets have been deleted", content_type="text/plain")

register_snippet_action_menu_item

Добавляет элемент в всплывающее меню действий при создании и редактировании сниппетов. Переданная в хук функция должна вернуть экземпляр wagtail.snippets.action_menu.ActionMenuItem. ActionMenuItem является подклассом компонента, поэтому отображение элемента меню можно настроить через template_name, get_context_data, render_html и Media. Кроме того, доступны следующие атрибуты и методы для переопределения:

Методы get_url, is_shown, get_context_data и render_html принимают словарь контекста, содержащий следующие поля:

from wagtail import hooks
from wagtail.snippets.action_menu import ActionMenuItem

class GuacamoleMenuItem(ActionMenuItem):
    name = 'action-guacamole'
    label = "Guacamole"

    def get_url(self, context):
        return "https://www.youtube.com/watch?v=dNJdJIwCF_Y"


@hooks.register('register_snippet_action_menu_item')
def register_guacamole_menu_item():
    return GuacamoleMenuItem(order=10)

construct_snippet_action_menu

Изменяет окончательный список элементов меню действий при создании и редактировании сниппетов. Переданная в хук функция получает список ActionMenuItem объектов, объект запроса и словарь контекста, как описано в register_snippet_action_menu_item, и должна изменить список элементов меню на месте.

@hooks.register('construct_snippet_action_menu')
def remove_delete_option(menu_items, request, context):
    menu_items[:] = [item for item in menu_items if item.name != 'delete']

Хук construct_snippet_action_menu вызывается после того, как элементы меню были отсортированы по их атрибутам порядка, поэтому установка порядка элемента меню не повлияет в этот момент. Вместо этого элементы можно переупорядочить, изменив их позицию в списке, при этом первый элемент будет выбран в качестве действия по умолчанию. Например, чтобы изменить действие по умолчанию на Удаление:

@hooks.register('construct_snippet_action_menu')
def make_delete_default_action(menu_items, request, context):
    for (index, item) in enumerate(menu_items):
        if item.name == 'delete':
            # move to top of list
            menu_items.pop(index)
            menu_items.insert(0, item)
            break

register_snippet_listing_buttons

Добавляет кнопки в список действий для сниппета в списке сниппетов. Это полезно при добавлении пользовательских действий в список, таких как переводы или сложный рабочий процесс.

Этот пример добавит простую кнопку в список:

from wagtail.snippets import widgets as wagtailsnippets_widgets

@hooks.register('register_snippet_listing_buttons')
def snippet_listing_buttons(snippet, user, next_url=None):
    yield wagtailsnippets_widgets.SnippetListingButton(
        'A page listing button',
        '/goes/to/a/url/',
        priority=10
    )

Аргументы, передаваемые в хук, следующие:

  • snippet — объект сниппета для создания кнопки
  • user — пользователь, просматривающий список сниппетов
  • next_url — URL, на который должна перенаправить связанное действие по завершении действия, если представление поддерживает это

Аргумент priority управляет порядком отображения кнопок. Кнопки упорядочены от низкого к высокому приоритету, поэтому кнопка с priority=10 будет отображаться перед кнопкой с priority=20.

construct_snippet_listing_buttons

Изменяет окончательный список кнопок списка сниппетов. Переданная в хук функция получает список SnippetListingButton объектов, пользователя и словарь контекста, как описано в register_snippet_listing_buttons, и должна изменить список элементов меню на месте.

@hooks.register('construct_snippet_listing_buttons')
def remove_snippet_listing_button_item(buttons, snippet, user, context=None):
    buttons.pop()  # Removes the 'delete' button

Массовые действия

Вспомогательные функции для регистрации и настройки массовых действий. См. здесь о том, как создать пользовательские массовые действия.

register_bulk_action

Регистрирует новое массовое действие для добавления в список массовых действий в проводнике.

Этот хук должен быть зарегистрирован с подклассом BulkAction. Например:

from wagtail.admin.views.bulk_action import BulkAction
from wagtail import hooks


@hooks.register("register_bulk_action")
class CustomBulkAction(BulkAction):
    display_name = _("Custom Action")
    action_type = "action"
    aria_label = _("Do custom action")
    template_name = "/path/to/template"
    models = [...]  # list of models the action should execute upon


    @classmethod
    def execute_action(cls, objects, **kwargs):
        for object in objects:
            do_something(object)
        return num_parent_objects, num_child_objects  # return the count of updated objects

before_bulk_action

Выполняет действия непосредственно перед выполнением массового действия (до вызова метода execute_action)

Этот хук может возвращать ответ HTTP. Например:

from wagtail import hooks

@hooks.register("before_bulk_action")
def hook_func(request, action_type, objects, action_class_instance):
  if action_type == 'delete':
    return HttpResponse(f"{len(objects)} objects would be deleted", content_type="text/plain")

after_bulk_action

Выполняет действия сразу после выполнения массового действия (после вызова метода execute_action)

Этот хук может возвращать ответ HTTP. Например:

from wagtail import hooks

@hooks.register("after_bulk_action")
def hook_func(request, action_type, objects, action_class_instance):
  if action_type == 'delete':
    return HttpResponse(f"{len(objects)} objects have been deleted", content_type="text/plain")

Журнал аудита

register_log_actions

См. Журнал аудита

Для добавления новых действий в реестр вызовите метод register_action с типом действия, его меткой и сообщением, которое будет отображаться в административных списках.

from django.utils.translation import gettext_lazy as _

from wagtail import hooks

@hooks.register('register_log_actions')
def additional_log_actions(actions):
    actions.register_action('wagtail_package.echo', _('Echo'), _('Sent an echo'))

В качестве альтернативы, для сообщения журнала, которое изменяется в зависимости от данных записи журнала, создайте подкласс wagtail.log_actions.LogFormatter, который переопределяет метод format_message, и используйте register_action в качестве декоратора для этого класса:

from django.utils.translation import gettext_lazy as _

from wagtail import hooks
from wagtail.log_actions import LogFormatter

@hooks.register('register_log_actions')
def additional_log_actions(actions):
    @actions.register_action('wagtail_package.greet_audience')
    class GreetingActionFormatter(LogFormatter):
        label = _('Greet audience')

        def format_message(self, log_entry):
            return _('Hello %(audience)s') % {
                'audience': log_entry.data['audience'],
            }

Изменено в версии 2.15: Класс LogFormatter был представлен. Раньше динамические сообщения достигались путём передачи вызываемого объекта как аргумента message методу register_action.

© 2014-present Torchbox Ltd and individual contributors.
All rights are reserved.
Licensed under the BSD License.
https://docs.wagtail.org/en/v3.0.3/reference/hooks.html

Spec-Zone.ru

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