Tagging¶
Wagtail provides tagging capabilities through the combination of two Django modules.
django-taggit - Which provides a general-purpose tagging implementation.
django-modelcluster - Which extends django-taggit’s
TaggableManager
to allow tag relations to be managed in memory without writing to the database, necessary for handling previews and revisions.
Custom tag models¶
In the above example, any newly-created tags will be added to django-taggit’s default Tag
model, which will be shared by all other models using the same recipe as well as Wagtail’s image and document models. In particular, this means that the autocompletion suggestions on tag fields will include tags previously added to other models. To avoid this, you can set up a custom tag model inheriting from TagBase
, along with a ‘through’ model inheriting from ItemBase
, which will provide an independent pool of tags for that page model.
from django.db import models
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey
from taggit.models import TagBase, ItemBase
class BlogTag(TagBase):
class Meta:
verbose_name = "blog tag"
verbose_name_plural = "blog tags"
class TaggedBlog(ItemBase):
tag = models.ForeignKey(
BlogTag, related_name="tagged_blogs", on_delete=models.CASCADE
)
content_object = ParentalKey(
to='demo.BlogPage',
on_delete=models.CASCADE,
related_name='tagged_items'
)
class BlogPage(Page):
...
tags = ClusterTaggableManager(through='demo.TaggedBlog', blank=True)
Within the admin, the tag field will automatically recognize the custom tag model being used and will offer autocomplete suggestions taken from that tag model.
Disabling free tagging¶
By default, tag fields work on a “free tagging” basis: editors can enter anything into the field, and upon saving, any tag text not recognized as an existing tag will be created automatically. To disable this behavior, and only allow editors to enter tags that already exist in the database, custom tag models accept a free_tagging = False
option:
from taggit.models import TagBase
from wagtail.snippets.models import register_snippet
@register_snippet
class BlogTag(TagBase):
free_tagging = False
class Meta:
verbose_name = "blog tag"
verbose_name_plural = "blog tags"
Here we have registered BlogTag
as a snippet, to provide an interface for administrators (and other users with the appropriate permissions) to manage the allowed set of tags. With the free_tagging = False
option set, editors can no longer enter arbitrary text into the tag field, and must instead select existing tags from the autocomplete dropdown.