片段¶
片段一般是页面中引用的一小段内容。用来动态定义一些内容,例如标题、边栏、脚注等。它可以在 Wagtail 后台管理界面中进行编辑。片段不从 Page
类继承,而使用 Django 模型类进行定义,所在不在页面树中显示。
片段通过 register_snippet
类修饰器进行注册,然后可以后台管理的片段子菜单中进行编辑。
片段缺少了页面的很多属性,例如排序、预定义的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。后台管理界面的编辑界面风格和页面风格类似,需要编辑的字段赋值给 panels
属性。片段编辑界面没有多个 Tab 页,也没有保存为草稿及提供审核的功能。
@register_snippet
告诉 Wagtail 将这个模型注册为片段。panels
列表定义了显示在编辑界面上的字段。通过 def __str__(self):
定义类对象的字符串显示内容也是很重要的,它输出的内容会显示在后台管理片段一览界面上,用来标识片段。
在模板标签中使用片段¶
在模板中最简单的使用片段方法是使用标签,使用 Django 中定制标签,具体可参考文档 django 定制模板标签 。这里简单说明一下过程,并解释和 Wagtail 相关的一些内容。
首先,在应用的 templatetags
文件夹中创建一个 Python 程序文件,例如 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()
返回全部对象。
下面是 demo/tags/adverts.html
模板使用自定义标签的示例:
{% for advert in adverts %}
<p>
<a href="{{ advert.url }}">
{{ advert.text }}
</a>
</p>
{% endfor %}
接下来在页面模板中,只需简单的引用片段模板标签即可:
{% load wagtailcore_tags demo_tags %}
...
{% block content %}
...
{% adverts %}
{% endblock %}
将页面绑定到片段¶
在上面的例子中,标签返回的广告列表是固定的,在每个页面上都一样。这在通用的边栏可以使用,有时我们需要根据页面内容来关联特定的广告。
这里需要在页面模型中定义外键关系关联到片段,然后在 content_panels
增加 SnippetChooserPanel
片段选择器为一个页面选择指定的片段。例如,在 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
中,而是放在内嵌子对象中。这里使用 BookPageAdvertPlacement
子对象
(这样起名的原因是每次将一个广告放入一个图书面面):
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'),
]
参考 页面打标签文档 以获取视图中使用标签的详细说明。