Модели страниц
Каждый тип страницы (также известный как тип контента) в 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', classname="full"),
InlinePanel('related_links', label="Related links"),
]
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 выберет правильный виджет в зависимости от типа поля, например, WYSIWYG-редактор для 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 Функциональность встраивания моделей предоставляется django-modelcluster, и тип поля ParentalKey необходимо импортировать оттуда:
from modelcluster.fields import ParentalKey
ParentalKey является подклассом Django ForeignKey, и принимает те же аргументы.
For example, the following inline model can be used to add related links (a list of name, url pairs) to the `BlogPage` model:
```python
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 QuerySet
Модели, производные от Page, не могут быть заданы по умолчанию с помощью стандартного подхода Django, добавления атрибута ordering к внутреннему классу Meta.
class NewsItemPage(Page):
publication_date = models.DateField()
...
class Meta:
ordering = ('-publication_date', ) # will not work
Это происходит потому, что Page принудительно упорядочивает QuerySet по пути. Вместо этого вы должны явно применить сортировку при создании QuerySet:
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/v3.0.3/topics/pages.html