Snippets¶
Snippets are pieces of content which do not necessitate a full webpage to render. They could be used for making secondary content, such as headers, footers, and sidebars, editable in the Wagtail admin. Snippets are Django models which do not inherit the Page
class and are thus not organized into the Wagtail tree. However, they can still be made editable by assigning panels and identifying the model as a snippet with the register_snippet
class decorator.
Snippets lack many of the features of pages, such as being orderable in the Wagtail admin or having a defined URL. Decide carefully if the content type you would want to build into a snippet might be more suited to a page.
Snippet Models¶
Here’s an example snippet model:
from django.db import models
from wagtail.admin.panels 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
The Advert
model uses the basic Django model class and defines two properties: text and URL. The editing interface is very close to that provided for Page
-derived models, with fields assigned in the panels
property. Snippets do not use multiple tabs of fields, nor do they provide the “save as draft” or “submit for moderation” features.
@register_snippet
tells Wagtail to treat the model as a snippet. The panels
list defines the fields to show on the snippet editing page. It’s also important to provide a string representation of the class through def __str__(self):
so that the snippet objects make sense when listed in the Wagtail admin.
Binding Pages to Snippets¶
In the above example, the list of adverts is a fixed list that is displayed via the custom template tag independent of any other content on the page. This might be what you want for a common panel in a sidebar, but, in another scenario, you might wish to display just one specific instance of a snippet on a particular page. This can be accomplished by defining a foreign key to the snippet model within your page model and adding a FieldPanel
to the page’s content_panels
list. For example, if you wanted to display a specific advert on a BookPage
instance:
# ...
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'),
# ...
]
The snippet could then be accessed within your template as page.advert
.
To attach multiple adverts to a page, the FieldPanel
can be placed on an inline child object of BookPage
rather than on BookPage
itself. Here, this child model is named BookPageAdvertPlacement
(so called because there is one such object for each time that an advert is placed on a 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"),
# ...
]
These child objects are now accessible through the page’s advert_placements
property, and from there we can access the linked Advert snippet as advert
. In the template for BookPage
, we could include the following:
{% for advert_placement in page.advert_placements.all %}
<p>
<a href="{{ advert_placement.advert.url }}">
{{ advert_placement.advert.text }}
</a>
</p>
{% endfor %}
Making Snippets Searchable¶
If a snippet model inherits from wagtail.search.index.Indexed
, as described in Indexing custom models, Wagtail will automatically add a search box to the chooser interface for that snippet type. For example, the Advert
snippet could be made searchable as follows:
...
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),
]
Tagging snippets¶
Adding tags to snippets is very similar to adding tags to pages. The only difference is that taggit.manager.TaggableManager
should be used in the place of 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'),
]
The documentation on tagging pages has more information on how to use tags in views.