Гаксы
При загрузке Wagtail будет искать любой приложение с файлом wagtail_hooks.py и выполнит его содержимое. Это предоставляет способ регистрации собственных функций для выполнения в определённые моменты выполнения Wagtail, такие как при сохранении страницы или при построении основного меню.
Примечание
Гаксы обычно используются для настройки поведения на уровне представления админ-панели Wagtail и фронта. Для настроек, которые затрагивают только поведение на уровне модели — например, для вызова внешней службы при добавлении страницы или документа — часто лучше использовать механизм сигналов Django механизм сигналов Django (см. также: Сигналы Wagtail), так как они не зависят от того, как пользователь пройдёт по административной части интерфейса.
Регистрация функций с помощью гака Wagtail выполняется с помощью декоратора @hooks.register:
from wagtail.core 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.core 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, поскольку элементы, добавленные через construct_main_menu, не будут проверены на is_shown.
from wagtail.core 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.core 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.core 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.core 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() на представлении администрирования, которое вы настроили). Дополнительно принимаются следующие именованные аргументы:
| name: | внутреннее имя, используемое для идентификации пункта меню; по умолчанию соответствует slug-форме метки. |
|---|---|
| icon_name: | иконка, отображаемая рядом с пунктом меню; нет значений по умолчанию, необязательно, но должна быть установлена для пунктов меню верхнего уровня, чтобы их можно было идентифицировать при сворачивании. |
| classnames: | дополнительные CSS-классы, применяемые к ссылке |
| order: | целое число, определяющее позицию элемента в меню |
Для пунктов меню, доступных только для суперпользователей, можно использовать подкласс wagtail.admin.menu.AdminOnlyMenuItem вместо MenuItem.
MenuItem может быть дополнительно расширен для настройки его инициализации или условного отображения/скрытия элемента для конкретных запросов (например, для применения проверок разрешений); см. исходный код (wagtail/admin/menu.py) для получения дополнительной информации.
from django.urls import reverse
from wagtail.core 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 URLconf и представлениях см. диспетчер URL.
from django.http import HttpResponse
from django.urls import path
from wagtail.core 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 admin «Другие поиски». Поведение этого гака аналогично register_admin_menu_item. Передаваемая в этот гак вызываемая функция должна вернуть экземпляр wagtail.admin.search.SearchArea. Новые элементы могут быть созданы из класса SearchArea путём передачи следующих параметров:
| label: | текст, отображаемый в поле «Другие поиски». |
|---|---|
| name: | внутреннее имя, используемое для идентификации опции поиска; по умолчанию соответствует slug-форме метки. |
| url: | URL целевой страницы поиска. |
| classnames: | произвольные CSS-классы, применяемые к ссылке |
| icon_name: | иконка для отображения рядом с меткой. |
| attrs: | дополнительные атрибуты HTML, применяемые к ссылке. |
| order: | целое число, определяющее позицию элемента в списке опций. |
Установка URL может быть выполнена с помощью reverse() на целевой странице поиска. К указанному URL будет добавлен параметр GET «q».
В шаблоне предоставляется тег search_other, модуль шаблонов wagtailadmin_tags. Этот тег принимает один необязательный параметр, current, который позволяет указать name опции поиска, которая в данный момент активна. Если параметр не указан, гак использует обратный поиск URL страницы для сравнения с параметром url.
SearchArea может быть расширен для настройки HTML-вывода, указания файлов JavaScript, необходимых для опции, или условного отображения/скрытия элемента для конкретных запросов (например, для применения проверок разрешений); см. исходный код (wagtail/admin/search.py) для получения дополнительной информации.
from django.urls import reverse
from wagtail.core 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
Возвращает набор объектов Permission для отображения в области администрирования групп.
from django.contrib.auth.models import Permission
from wagtail.core 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.core 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.core 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.core 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.core 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.html import format_html
from wagtail.core import hooks
@hooks.register('insert_global_admin_js')
def global_admin_js():
return format_html(
'<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.core 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.core 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.core 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.
ActionMenuItem является подклассом Компонента, поэтому отрисовка элемента меню может настраиваться с помощью template_name, get_context_data, render_html и Media. Кроме того, доступны следующие атрибуты и методы для переопределения:
| order: | целое число (по умолчанию 100), определяющее положение элемента в меню. Также может быть передано в качестве ключевого аргумента в конструктор объекта. Элемент с наименьшим номером в этой последовательности будет выбран в качестве элемента меню по умолчанию; по умолчанию это «Сохранить черновик» (с order 0). |
|---|---|
| label: | отображаемый текст элемента меню |
| get_url: | метод, возвращающий URL для элемента меню; по умолчанию возвращает None, что заставляет элемент меню вести себя как кнопку отправки формы. |
| name: | значение атрибута name кнопки отправки, если не указан URL |
| icon_name: | иконка для отображения рядом с элементом меню |
| classname: | значение атрибута class для добавления к элементу кнопки |
| is_shown: | метод, возвращающий логическое значение, указывающее, должен ли отображаться элемент меню; по умолчанию — true, за исключением редактирования заблокированной страницы |
Методы get_url, is_shown, get_context_data и render_html принимают словарь контекста, содержащий следующие поля:
| view: | имя текущего представления: 'create', 'edit' или 'revisions_revert'
|
|---|---|
| page: | Для view = 'edit' или 'revisions_revert', страница, которая редактируется |
| parent_page: | Для view = 'create', родительская страница создаваемой страницы |
| request: | Текущий объект запроса |
| user_page_permissions: | |
объект UserPagePermissionsProxy для текущего пользователя, для проверки разрешений | |
from wagtail.core 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.core 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.core 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.core 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.
Выборщики
construct_page_chooser_queryset
Вызывается при отрисовке представления выбора страниц, чтобы разрешить настройку набора запросов отображения страниц. Вызываемый объект, переданный в хук, получит текущий набор запросов страниц и объект запроса и должен вернуть набор запросов страниц (либо исходный, либо новый).
from wagtail.core 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
Вызывается при отрисовке представления выбора документов, чтобы разрешить настройку набора запросов отображения документов. Вызываемый объект, переданный в хук, получит текущий набор запросов документов и объект запроса, и должен вернуть набор запросов документов (либо исходный, либо новый).
from wagtail.core 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
Вызывается при отрисовке представления выбора изображений, чтобы разрешить настройку набора запросов отображения изображений. Вызываемый объект, переданный в хук, получит текущий набор запросов изображений и объект запроса, и должен вернуть набор запросов изображений (либо исходный, либо новый).
from wagtail.core 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
Вызывается при отрисовке представления проводника страниц, чтобы разрешить настройку набора запросов отображения страниц. Вызываемый объект, переданный в хук, получит объект родительской страницы, текущий набор запросов страниц и объект запроса, и должен вернуть набор запросов страниц (либо исходный, либо новый).
from wagtail.core 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- объектPagePermissionTester, который можно запросить, чтобы определить права текущего пользователя на данной странице -
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- объектPagePermissionTester, который можно запросить, чтобы определить права текущего пользователя на данной странице -
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.core 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.core 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.core 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
Вызывается при удалении фрагмента. Переданная в хук функция получит экземпляр(ы) модели в виде набора запросов вместе с объектом запроса. Если функция возвращает HttpResponse, этот ответ будет немедленно возвращен пользователю, и Wagtail не будет продолжать вызывать redirect() в просмотр списка.
from django.http import HttpResponse
from wagtail.core 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
Вызывается в начале просмотра удаления фрагмента. Переданная в хук функция получит экземпляр(ы) модели в виде набора запросов вместе с объектом запроса. Если функция возвращает HttpResponse, этот ответ будет немедленно возвращен пользователю, и Wagtail не будет продолжать вызывать redirect() в просмотр списка.
from django.http import HttpResponse
from wagtail.core 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. Кроме того, можно переопределить следующие атрибуты и методы:
| order: | целое число (по умолчанию 100), определяющее позицию элемента в меню. Также может быть передано в качестве именованного аргумента конструктору объекта. Элемент с наименьшим номером в этом списке будет выбран по умолчанию; по умолчанию это «Сохранить черновик» (у которого order равен 0). |
|---|---|
| label: | отображаемый текст элемента меню |
| get_url: | метод, возвращающий URL для элемента меню; по умолчанию возвращает None, что делает элемент меню кнопкой отправки формы |
| name: | значение атрибута name кнопки отправки, если URL не указан |
| icon_name: | иконка, отображаемая рядом с элементом меню |
| classname: | значение атрибута class для добавления к элементу кнопки |
| is_shown: | метод, возвращающий булево значение, указывающее, должен ли отображаться элемент меню; по умолчанию true, за исключением редактирования заблокированной страницы |
Методы get_url, is_shown, get_context_data и render_html принимают словарь контекста, содержащий следующие поля:
| view: | имя текущего просмотра: 'create' или 'edit'
|
|---|---|
| model: | Класс модели фрагмента |
| instance: | При view = 'edit', экземпляр, который редактируется |
| request: | Текущий объект запроса |
from wagtail.core 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 вызывается после сортировки элементов меню по их атрибутам order, и поэтому установка порядка элемента меню в этот момент не повлияет. Вместо этого элементы можно переупорядочить, изменив их позицию в списке, при этом первый элемент будет выбран по умолчанию. Например, чтобы изменить действие по умолчанию на Удалить:
@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.core 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.core 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.core 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.core import hooks
@hooks.register('register_log_actions')
def additional_log_actions(actions):
actions.register_action('wagtail_package.echo', _('Echo'), _('Sent an echo'))
В качестве альтернативы, для сообщения журнала, которое изменяется в зависимости от данных записи журнала, создайте подкласс wagtail.core.log_actions.LogFormatter, который переопределяет метод format_message, и используйте register_action в качестве декоратора для этого класса:
from django.utils.translation import gettext_lazy as _
from wagtail.core import hooks
from wagtail.core.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/v2.16.3/reference/hooks.html