Сниппеты
Сниппеты — это фрагменты контента, для отображения которых не требуется полная веб-страница. Их можно использовать для создания вторичного контента, такого как заголовки, подвалы и боковые панели, которые можно редактировать в админке Wagtail. Сниппеты — это модели Django, которые не наследуют класс Page и поэтому не организованы в дереве Wagtail. Однако их можно сделать редактируемыми, назначив панели и определив модель как сниппет с помощью декоратора класса register_snippet.
У сниппетов отсутствуют многие функции страниц, такие как возможность упорядочения в админке Wagtail или определение URL. Тщательно решите, подходит ли тип контента, который вы хотите создать в виде сниппета, для страницы.
Модели сниппетов
Вот пример модели сниппета:
from django.db import models
from wagtail.admin.edit_handlers import FieldPanel
from wagtail.snippets.models import register_snippet
...
@register_snippet
class Advert(models.Model):
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
panels = [
FieldPanel('url'),
FieldPanel('text'),
]
def __str__(self):
return self.text
Модель Advert использует базовый класс модели Django и определяет два свойства: текст и URL. Интерфейс редактирования очень похож на интерфейс для моделей, наследуемых от Page, с полями, заданными в свойстве panels. Сниппеты не используют несколько вкладок с полями, а также не предоставляют функций «сохранить как черновик» или «отправить на модерацию».
@register_snippet сообщает Wagtail, что модель должна обрабатываться как сниппет. Список panels определяет поля, которые должны отображаться на странице редактирования сниппета. Также важно предоставить строковое представление класса через def __str__(self):, чтобы объекты сниппетов были понятны при отображении в админке Wagtail.
Включение сниппетов в теги шаблонов
Самый простой способ сделать ваши сниппеты доступными для шаблонов — это использование тега шаблона. Это в основном делается с помощью стандартного Django, поэтому, возможно, будет полезно ознакомиться с документацией Django по настраиваемым тегам шаблонов Django. Тем не менее, мы рассмотрим основы и отметим моменты, которые следует учесть для Wagtail.
Сначала добавьте новый файл Python в папку templatetags вашего приложения — например, myproject/demo/templatetags/demo_tags.py. Нам нужно будет загрузить некоторые модули Django и модели вашего приложения, а также подготовить декоратор register:
from django import template
from demo.models import Advert
register = template.Library()
...
# Advert snippets
@register.inclusion_tag('demo/tags/adverts.html', takes_context=True)
def adverts(context):
return {
'adverts': Advert.objects.all(),
'request': context['request'],
}
@register.inclusion_tag() принимает два параметра: шаблон и булево значение, определяющее, должен ли этот шаблон получать контекст запроса. Включать контекст запроса в свои пользовательские теги шаблонов — хорошая идея, поскольку некоторые теги шаблонов, специфичные для Wagtail, например, pageurl, нуждаются в контексте для корректной работы. Функция тега шаблона может принимать аргументы и фильтровать объявления, чтобы вернуть конкретный экземпляр модели, но для краткости мы будем использовать Advert.objects.all().
Вот содержимое шаблона, используемого этим тегом шаблона:
{% for advert in adverts %}
<p>
<a href="{{ advert.url }}">
{{ advert.text }}
</a>
</p>
{% endfor %}
Затем, в ваших собственных шаблонах страниц, вы можете включить тег шаблона сниппета следующим образом:
{% load wagtailcore_tags demo_tags %}
...
{% block content %}
...
{% adverts %}
{% endblock %}
Связывание страниц со сниппетами
В приведенном выше примере список объявлений — это фиксированный список, который отображается с помощью пользовательского тега шаблона независимо от другого контента на странице. Возможно, это то, что вам нужно для общей панели на боковой панели, но в другом случае вы можете захотеть отобразить только один конкретный экземпляр сниппета на определенной странице. Это можно сделать, определив внешний ключ к модели сниппета в модели вашей страницы и добавив SnippetChooserPanel в список content_panels страницы. Например, если вы хотите отобразить конкретное объявление на экземпляре BookPage:
from wagtail.snippets.edit_handlers import SnippetChooserPanel
# ...
class BookPage(Page):
advert = models.ForeignKey(
'demo.Advert',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
content_panels = Page.content_panels + [
SnippetChooserPanel('advert'),
# ...
]
Затем к сниппету можно обратиться в шаблоне как к page.advert.
Чтобы прикрепить несколько объявлений к странице, SnippetChooserPanel можно поместить на встроенный дочерний объект BookPage, а не на BookPage само по себе. Здесь эта дочерняя модель называется BookPageAdvertPlacement (так названа потому, что существует один такой объект для каждого случая размещения объявления на BookPage):
from django.db import models
from wagtail.core.models import Page, Orderable
from wagtail.snippets.edit_handlers import SnippetChooserPanel
from modelcluster.fields import ParentalKey
...
class BookPageAdvertPlacement(Orderable, models.Model):
page = ParentalKey('demo.BookPage', on_delete=models.CASCADE, related_name='advert_placements')
advert = models.ForeignKey('demo.Advert', on_delete=models.CASCADE, related_name='+')
class Meta(Orderable.Meta):
verbose_name = "advert placement"
verbose_name_plural = "advert placements"
panels = [
SnippetChooserPanel('advert'),
]
def __str__(self):
return self.page.title + " -> " + self.advert.text
class BookPage(Page):
...
content_panels = Page.content_panels + [
InlinePanel('advert_placements', label="Adverts"),
# ...
]
Теперь к этим дочерним объектам можно получить доступ через свойство страницы advert_placements, а оттуда мы можем получить доступ к связанному сниппету объявления как к advert. В шаблоне для BookPage мы могли бы включить следующее:
{% for advert_placement in page.advert_placements.all %}
<p>
<a href="{{ advert_placement.advert.url }}">
{{ advert_placement.advert.text }}
</a>
</p>
{% endfor %}
Делаем сниппеты подлежащими поиску
Если модель сниппета наследует от wagtail.search.index.Indexed, как описано в индексировании пользовательских моделей, Wagtail автоматически добавит поле поиска в интерфейс выбора для этого типа сниппета. Например, сниппет Advert можно сделать подлежащим поиску следующим образом:
...
from wagtail.search import index
...
@register_snippet
class Advert(index.Indexed, models.Model):
url = models.URLField(null=True, blank=True)
text = models.CharField(max_length=255)
panels = [
FieldPanel('url'),
FieldPanel('text'),
]
search_fields = [
index.SearchField('text', partial_match=True),
]
Тегирование сниппетов
Добавление тегов к сниппетам очень похоже на добавление тегов к страницам. Единственное различие в том, что taggit.manager.TaggableManager следует использовать вместо ClusterTaggableManager.
from modelcluster.fields import ParentalKey
from modelcluster.models import ClusterableModel
from taggit.models import TaggedItemBase
from taggit.managers import TaggableManager
class AdvertTag(TaggedItemBase):
content_object = ParentalKey('demo.Advert', on_delete=models.CASCADE, related_name='tagged_items')
@register_snippet
class Advert(ClusterableModel):
...
tags = TaggableManager(through=AdvertTag, blank=True)
panels = [
...
FieldPanel('tags'),
]
В документации по тегированию страниц есть больше информации о том, как использовать теги в представлениях.
© 2014-present Torchbox Ltd and individual contributors.
All rights are reserved.
Licensed under the BSD License.
https://docs.wagtail.org/en/v2.16.3/topics/snippets.html