作为 Django 模型,片段可以在 Django 模板中使用自定义模板标签来呈现。或者,它们也可以作为 Wagtail 页面渲染过程的一部分。

在模板标签中包含片段

使片段可用于模板的最简单方法是使用模板标签。这主要是使用 vanilla Django 完成的,因此查看 自定义 template tags 的 Django 文档可能会更有帮助。不过,我们将回顾一下基础知识,并指出对 Wagtail 的任何注意事项。

首先,将新的 python 文件添加到应用程序内的 templatetags 文件夹中 - 例如 myproject/demo/templatetags/demo_tags.py 。我们需要加载一些 Django 模块和我们应用程序的模型,并准备好 register 装饰器:

from django import template
from demo.models import Advert

register = template.Library()

# ...

# 广告片段
@register.inclusion_tag('demo/tags/adverts.html', takes_context=True)
def adverts(context):
    return {
        'adverts': Advert.objects.all(),
        'request': context['request'],
    }

@register.inclusion_tag() 采用两个变量:一个模板和一个关于是否应向该模板传递请求上下文的 boolean 。在自定义模板标签中包含请求上下文是一个好主意,因为一些特定于 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 %}

将页面绑定到片段

在上面的示例中,广告列表是一个固定列表,通过自定义模板标签显示,独立于页面上的任何其他内容。这可能是您想要的侧边栏中的公共面板,但是,在另一种情况下,您可能希望在特定页面上仅显示代码片段的一个特定实例。这可以通过在页面模型中定义片段模型的外键并将 [FieldPanel] 添加到页面的 content_panels 列表来完成。例如,如果您想在 BookPage 实例上显示特定广告:

  # ...
  class BookPage(Page):
      advert = models.ForeignKey(
          'demo.Advert',
          null=True,
          blank=True,
          on_delete=models.SET_NULL,
          related_name='+'
      )

      content_panels = Page.content_panels + [
          FieldPanel('advert'),
          # ...
      ]

然后可以在模板中以 page.advert 的形式访问该代码段。

要将多个广告附加到页面, FieldPanel 可以放置在 BookPage 的内联子对象上,而不是放置在 BookPage 本身上。在这里,这个子模型被命名为 BookPageAdvertPlacement (之所以这样称呼是因为每次在 BookPage 上放置广告时都会有一个这样的对象):

from django.db import models

from wagtail.models import Page, Orderable

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 = [
        FieldPanel('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 代码段作为 advert 访问。在 BookPage 的模板中,我们可以包含以下内容:

{% for advert_placement in page.advert_placements.all %}
    <p>
        <a href="{{ advert_placement.advert.url }}">
            {{ advert_placement.advert.text }}
        </a>
    </p>
{% endfor %}