Модели страниц
Каждый тип страницы (также известный как тип контента) в Wagtail представлен моделью Django. Все модели страниц должны наследоваться от класса wagtail.models.Page.
Поскольку все типы страниц являются моделями Django, вы можете использовать любой тип поля, предоставляемый Django. Полный список типов полей, которые вы можете использовать, см. в Справочнике по полям моделей. Wagtail также предоставляет wagtail.fields.RichTextField для редактирования форматированного текста с помощью WYSIWYG-редактора.
Примечание
Если вы еще не знакомы с моделями Django, ознакомьтесь со ссылками для начала работы:
Пример модели страницы Wagtail
Этот пример представляет типичную запись блога:
from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.models import Page, Orderable
from wagtail.fields import RichTextField
from wagtail.admin.panels import FieldPanel, MultiFieldPanel, InlinePanel
from wagtail.search import index
class BlogPage(Page):
# Database fields
body = RichTextField()
date = models.DateField("Post date")
feed_image = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
# Search index configuration
search_fields = Page.search_fields + [
index.SearchField('body'),
index.FilterField('date'),
]
# Editor panels configuration
content_panels = Page.content_panels + [
FieldPanel('date'),
FieldPanel('body'),
InlinePanel('related_links', heading="Related links", label="Related link"),
]
promote_panels = [
MultiFieldPanel(Page.promote_panels, "Common page configuration"),
FieldPanel('feed_image'),
]
# Parent page / subpage type rules
parent_page_types = ['blog.BlogIndex']
subpage_types = []
class BlogPageRelatedLink(Orderable):
page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='related_links')
name = models.CharField(max_length=255)
url = models.URLField()
panels = [
FieldPanel('name'),
FieldPanel('url'),
]
Примечание
Убедитесь, что имена ваших полей не совпадают с именами ваших классов. Это приведет к ошибкам из-за того, как Django обрабатывает отношения (подробнее). В наших примерах мы избежали этого, добавив "Page" к каждому имени модели.
Создание моделей страниц
Здесь мы опишем каждый раздел вышеприведенного примера, чтобы помочь вам создать собственные модели страниц.
Поля базы данных
Каждый тип страницы Wagtail — это модель Django, представленная в базе данных как отдельная таблица.
У каждого типа страницы может быть свой набор полей. Например, новостная статья может иметь текст тела и дату публикации, в то время как страница события может потребовать отдельных полей для места проведения и времени начала/окончания.
В Wagtail вы можете использовать любой класс поля Django. Большинство классов полей, предоставляемых приложениями сторонних разработчиков, также должны работать.
Wagtail также предоставляет несколько собственных классов полей:
-
RichTextField— для форматированного текста -
StreamField— поле контента на основе блоков (см.: Динамический контент страницы с помощью StreamField)
Для тегирования Wagtail полностью поддерживает django-taggit, поэтому мы рекомендуем использовать его.
Поиск
Атрибут search_fields определяет, какие поля добавляются в индекс поиска и как они индексируются.
Это должен быть список SearchField и FilterField объектов. SearchField добавляет поле для полнотекстового поиска. FilterField добавляет поле для фильтрации результатов. Одно поле может быть индексировано как с помощью SearchField, так и с помощью FilterField одновременно (но только по одному экземпляру каждого).
В приведенном выше примере мы проиндексировали body для полнотекстового поиска и date для фильтрации.
Аргументы, которые принимают эти типы полей, описаны в дополнительных полях индексирования.
Панели редактора
Есть несколько атрибутов для определения того, как поля страницы будут организованы в интерфейсе редактора страницы:
-
content_panels— для контента, такого как основной текст -
promote_panels— для метаданных, таких как теги, миниатюрное изображение и SEO-заголовок -
settings_panels— для настроек, таких как дата публикации
Каждый из этих атрибутов устанавливается в список Panel объектов, определяющих, какие поля отображаются на каких вкладках и как они структурированы на каждой вкладке.
Вот краткое описание Panel классов, которые Wagtail предоставляет "из коробки". Полные описания см. в Типы панелей.
Основные
Эти классы позволяют редактировать поля модели. Класс FieldPanel выберет правильный виджет на основе типа поля, например, редактор форматированного текста для RichTextField, или выбор изображения для ForeignKey к модели изображения. FieldPanel также предоставляет интерфейс выбора страницы для ForeignKey к моделям страниц, но для более точного управления типами страниц, которые можно выбрать, PageChooserPanel предоставляет дополнительные параметры настройки.
Изменено в версии 3.0: Ранее некоторые типы полей требовали специальных панелей: StreamFieldPanel, ImageChooserPanel, DocumentChooserPanel и SnippetChooserPanel. Теперь все они обрабатываются FieldPanel.
Структурные
Они используются для структурирования полей в интерфейсе.
Настройка интерфейса редактора страницы
Интерфейс редактора страницы можно настроить более детально. См. Настройка интерфейса редактирования.
Правила типа родительской страницы / дочерней страницы
Эти два атрибута позволяют управлять тем, где типы страниц могут быть использованы на вашем сайте. Это позволяет задавать правила, например, «записи блога могут создаваться только под индексом блога».
Оба принимают список классов моделей или имен моделей. Имена моделей имеют формат app_label.ModelName. Если app_label опущено, предполагается то же приложение.
-
parent_page_typesограничивает типы страниц, под которыми можно создать данный тип -
subpage_typesограничивает типы страниц, которые можно создать под этим типом
По умолчанию любой тип страницы может быть создан под любым типом страницы, и нет необходимости устанавливать эти атрибуты, если это желаемое поведение.
Установка parent_page_types в пустой список — хороший способ предотвратить создание определенного типа страницы в интерфейсе редактора.
Описания страниц
В каждой модели страницы Wagtail вы можете добавить полезный текст описания, похожий на атрибут модели help_text. Добавление page_description к вашей модели страницы добавит краткое описание, которое можно увидеть при создании новой страницы, редактировании существующей страницы или при запросе выбора типа дочерней страницы.
class LandingPage(Page):
page_description = "Use this page for converting users"
URL-адреса страниц
Наиболее распространенный метод получения URL-адресов страниц — использование тега шаблона {% pageurl %}. Поскольку он вызывается из шаблона, pageurl автоматически включает указанные ниже оптимизации. Дополнительную информацию см. в pageurl.
Модели страниц также включают несколько методов низкого уровня для переопределения или доступа к URL-адресам страниц.
Настройка шаблонов URL-адресов для модели страницы
Метод Page.get_url_parts(request) обычно не вызывается напрямую, но может быть переопределен для определения пользовательской маршрутизации URL-адресов для данной модели страницы. Он должен возвращать кортеж (site_id, root_url, page_path), которые используются get_url и get_full_url (см. ниже) для построения URL-адреса данного типа страницы.
При переопределении get_url_parts(), вы должны принять *args, **kwargs:
def get_url_parts(self, *args, **kwargs):
и передать их в момент вызова get_url_parts на super (если применимо), например:
super().get_url_parts(*args, **kwargs)
Хотя вы можете передать только ключевое слово request, передача всех аргументов как есть обеспечивает совместимость с любыми будущими изменениями сигнатур этих методов.
Дополнительную информацию см. в wagtail.models.Page.get_url_parts().
Получение URL-адресов для экземпляров страниц
Метод Page.get_url(request) может вызываться всякий раз, когда требуется URL-адрес страницы. По умолчанию он возвращает локальные URL-адреса (без протокола или домена), если определяет, что страница находится на текущем сайте (через имя хоста в request); в противном случае возвращается полный URL-адрес, включающий протокол и домен. Всякий раз, когда это возможно, необязательный аргумент request должен быть включен для включения кеширования URL-адресов на уровне сайта на уровне запроса и для облегчения генерации локальных URL-адресов.
Типичный случай использования get_url(request) — в любом пользовательском теге шаблона, который ваш проект может включать для создания навигационных меню. При написании такого пользовательского тега шаблона убедитесь, что он включает takes_context=True и используйте context.get('request') для безопасной передачи запроса или None при отсутствии запроса в контексте.
Дополнительную информацию см. в wagtail.models.Page.get_url().
В случае необходимости полного URL-адреса (включающего протокол и домен), можно использовать Page.get_full_url(request). Всякий раз, когда это возможно, необязательный аргумент request должен быть включен для включения кеширования URL-адресов на уровне сайта на уровне запроса.
Дополнительную информацию см. в wagtail.models.Page.get_full_url().
Рендеринг шаблонов
Каждой модели страницы можно задать HTML-шаблон, который отображается, когда пользователь переходит на страницу на переднем плане сайта. Это самый простой и распространенный способ отображения содержимого Wagtail конечным пользователям (но не единственный).
Добавление шаблона для модели страницы
Wagtail автоматически выбирает имя шаблона на основе метки приложения и имени класса модели.
Формат: <app_label>/<model_name (snake cased)>.html
Например, шаблон для страницы блога выше будет: blog/blog_page.html
Вам просто нужно создать шаблон в месте, где к нему можно получить доступ с этим именем.
Контекст шаблона
Wagtail рендерит шаблоны с переменной page, привязанной к экземпляру страницы, который рендерится. Используйте её для доступа к содержимому страницы. Например, чтобы получить заголовок текущей страницы, используйте {{ page.title }}. Также доступны все переменные, предоставляемые обработчиками контекста.
Настройка контекста шаблона
У всех страниц есть метод get_context, который вызывается всякий раз, когда рендерится шаблон, и возвращает словарь переменных для привязки к шаблону.
Чтобы добавить больше переменных в контекст шаблона, вы можете переопределить этот метод:
class BlogIndexPage(Page):
...
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
# Add extra variables and return the updated context
context['blog_entries'] = BlogPage.objects.child_of(self).live()
return context
Затем переменные можно использовать в шаблоне:
{{ page.title }}
{% for entry in blog_entries %}
{{ entry.title }}
{% endfor %}
Изменение шаблона
Установите атрибут template в классе, чтобы использовать другой файл шаблона:
class BlogPage(Page):
...
template = 'other_template.html'
Динамический выбор шаблона
Шаблон можно изменить на уровне экземпляра, определив метод get_template в классе страницы. Этот метод вызывается каждый раз при рендеринге страницы:
class BlogPage(Page):
...
use_other_template = models.BooleanField()
def get_template(self, request, *args, **kwargs):
if self.use_other_template:
return 'blog/other_blog_page.html'
return 'blog/blog_page.html'
В этом примере страницы, у которых установлено булевое поле use_other_template, будут использовать шаблон blog/other_blog_page.html. Все остальные страницы будут использовать стандартный шаблон blog/blog_page.html.
Шаблоны AJAX
Если вы хотите добавить функциональность AJAX на страницу, например, постраничное представление, которое обновляется на странице без полной перезагрузки, вы можете установить атрибут ajax_template для указания альтернативного шаблона, который будет использоваться при запросе страницы через вызов AJAX (как указано в заголовке X-Requested-With: XMLHttpRequest HTTP):
class BlogPage(Page):
...
ajax_template = 'other_template_fragment.html'
template = 'other_template.html'
Больше контроля над рендерингом страницы
У всех классов страниц есть метод serve(), который внутренне вызывает методы get_context и get_template и рендерит шаблон. Этот метод похож на функцию представления Django, принимающую объект Django Request и возвращающую объект Django Response.
Этот метод также можно переопределить для полного контроля над рендерингом страницы.
Например, вот способ сделать так, чтобы страница отвечала JSON-представлением себя:
from django.http import JsonResponse
class BlogPage(Page):
...
def serve(self, request):
return JsonResponse({
'title': self.title,
'body': self.body,
'date': self.date,
# Resizes the image to 300px width and gets a URL to it
'feed_image': self.feed_image.get_rendition('width-300').url,
})
Встроенные модели
Wagtail может встраивать содержимое других моделей в страницу. Это полезно для создания повторяющихся полей, таких как связанные ссылки или элементы для отображения в карусели. Содержимое встроенной модели также имеет версионирование вместе с остальным содержимым страницы.
Для каждой встроенной модели требуется следующее:
- Она должна наследоваться от
wagtail.models.Orderable - Она должна иметь связь
ParentalKeyс родительской моделью
Примечание
Функция встраивания модели предоставляется django-modelcluster, и тип поля ParentalKey должен быть импортирован оттуда:
from modelcluster.fields import ParentalKey
ParentalKey является подклассом ForeignKey Django, и принимает те же аргументы.
Например, следующую встроенную модель можно использовать для добавления связанных ссылок (списка пар «имя», «URL») к модели BlogPage:
from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.models import Orderable
class BlogPageRelatedLink(Orderable):
page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='related_links')
name = models.CharField(max_length=255)
url = models.URLField()
panels = [
FieldPanel('name'),
FieldPanel('url'),
]
Чтобы добавить это в интерфейс администратора, используйте класс панели редактирования InlinePanel:
content_panels = [
...
InlinePanel('related_links', label="Related links"),
]
Первый аргумент должен соответствовать значению атрибута related_name модели ParentalKey.
Работа со страницами
Wagtail использует возможность многотабличного наследования Django для возможности использования нескольких моделей страниц в одном дереве.
Каждая страница добавляется как в встроенную модель Wagtail Page, так и в пользовательскую модель (такую, как модель BlogPage созданную ранее).
Страницы могут существовать в коде Python в двух формах: экземпляр Page или экземпляр модели страницы.
При работе с несколькими типами страниц вместе, вы обычно используете экземпляры модели Wagtail Page, которые не дают вам доступа к каким-либо полям, специфичным для их типа.
# Get all pages in the database >>> from wagtail.models import Page >>> Page.objects.all() [<Page: Homepage>, <Page: About us>, <Page: Blog>, <Page: A Blog post>, <Page: Another Blog post>]
При работе с одним типом страницы вы можете работать с экземплярами пользовательской модели. Они предоставляют доступ ко всем полям, доступным в Page, вместе с любыми пользовательскими полями для этого типа.
# Get all blog entries in the database >>> BlogPage.objects.all() [<BlogPage: A Blog post>, <BlogPage: Another Blog post>]
Вы можете преобразовать объект Page в его более специфический пользовательский эквивалент с помощью свойства .specific. Это может привести к дополнительной выборке из базы данных.
>>> page = Page.objects.get(title="A Blog post") >>> page <Page: A Blog post> # Note: the blog post is an instance of Page so we cannot access body, date or feed_image >>> page.specific <BlogPage: A Blog post>
Советы
Дружественные имена моделей
Вы можете сделать имена моделей более удобными для пользователей Wagtail, используя внутренний класс Django Meta с verbose_name, например:
class HomePage(Page):
...
class Meta:
verbose_name = "homepage"
Когда пользователям предлагается выбор страниц для создания, список типов страниц генерируется путем разделения имён моделей по заглавным буквам. Таким образом, модель HomePage получила бы имя «Главная страница», что немного неудобно. Определение verbose_name как в примере выше изменит это на «Главная», что немного более стандартно.
Порядок набора запросов страниц
Модели, производные от Page, не могут быть заданы по умолчанию по порядку с помощью стандартного подхода Django, добавив атрибут ordering к внутреннему классу Meta.
class NewsItemPage(Page):
publication_date = models.DateField()
...
class Meta:
ordering = ('-publication_date', ) # will not work
Это происходит потому, что Page принудительно упорядочивает наборы запросов по пути. Вместо этого вы должны явно применить сортировку при построении набора запросов:
news_items = NewsItemPage.objects.live().order_by('-publication_date')
Пользовательские менеджеры страниц
Вы можете добавить пользовательский менеджер Manager к вашему классу Page. Любые пользовательские менеджеры должны наследоваться от wagtail.models.PageManager:
from django.db import models
from wagtail.models import Page, PageManager
class EventPageManager(PageManager):
""" Custom manager for Event pages """
class EventPage(Page):
start_date = models.DateField()
objects = EventPageManager()
В качестве альтернативы, если вам нужно добавить только дополнительные методы QuerySet, вы можете наследоваться от wagtail.models.PageQuerySet для создания пользовательского менеджера Manager:
from django.db import models
from django.utils import timezone
from wagtail.models import Page, PageManager, PageQuerySet
class EventPageQuerySet(PageQuerySet):
def future(self):
today = timezone.localtime(timezone.now()).date()
return self.filter(start_date__gte=today)
EventPageManager = PageManager.from_queryset(EventPageQuerySet)
class EventPage(Page):
start_date = models.DateField()
objects = EventPageManager()
© 2014-present Torchbox Ltd and individual contributors.
All rights are reserved.
Licensed under the BSD License.
https://docs.wagtail.org/en/stable/topics/pages.html