Wagtail/Django Taggit - уникальный пул тегов для каждого набора дочерних страниц

Для примера предположим, что мы хотим создать несколько блогов, но в одном приложении. В каждом блоге есть записи, которые являются дочерними тегами каждого соответствующего блога. Можно ли настроить Taggit таким образом, чтобы пул тегов каждого блога оставался отдельным друг от друга. Скажем, если один блог посвящен еде, а другой - автомобилям, вы не хотите, чтобы предложения автозаполнения из одного появлялись в другом.

Я попытался выполнить пример "Пользовательские модели тегов" в документации Wagtail здесь. Безрезультатно.

Я также попробовал воспользоваться предложением из этого вопроса на stackoverflow.

Вот код из документации Wagtail, приведенной выше:

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)

Заранее спасибо!

Вот как это работает на моем сайте - 2 класса страниц блогов (TechBlogDetailPage и PersonalBlogDetailPage), которые оба наследуют базовый класс страницы блога (BlogDetailPage). Для каждого типа существует класс тегов, который создает родительский ключ на 2 классах страниц блогов (а не на унаследованной модели).

# tags.py
from django.db import models
from modelcluster.models import ParentalKey
from taggit.models import TaggedItemBase

class TechBlogPageTag(TaggedItemBase):
    content_object = ParentalKey(
        'TechBlogDetailPage',
        related_name='tagged_items',
        on_delete=models.CASCADE,
    )

class PersonalBlogPageTag(TaggedItemBase):
    content_object = ParentalKey(
        'PersonalBlogDetailPage',
        related_name='tagged_items',
        on_delete=models.CASCADE,
    )
# models.py
from .tags import PersonalBlogPageTag, TechBlogPageTag

class TechBlogDetailPage(BlogDetailPage):
    parent_page_types = ['blog.TechBlogListingPage']
    ....
    tags = ClusterTaggableManager(through=TechBlogPageTag, blank=True)
    ....

class PersonalBlogDetailPage(BlogDetailPage):
    parent_page_types = ['blog.PersonalBlogListingPage']
    ....
    tags = ClusterTaggableManager(through=PersonalBlogPageTag, blank=True)
    ....

Теги, созданные в Tech Blog Pages, доступны только на Tech Blog Pages и недоступны на Personal Blog Pages & и наоборот.

Вот как мы создаем теги для каждого сайта. Возможно, вы сможете адаптировать его для своего случая.

from django.db import models
from modelcluster.contrib.taggit import ClusterTaggableManager
from modelcluster.fields import ParentalKey, ParentalManyToManyField
from taggit.models import TaggedItemBase, TagBase
from wagtail.models import Page, Site


class SiteSpecificTag(TagBase):
    """
    Our custom Tag model, which lets us associate tags with a specific Site.
    """
    site = models.ForeignKey(Site, related_name='tags', on_delete=models.CASCADE)
    # We need to redefine the name field to make it non-unique.
    name = models.CharField(verbose_name='Name', max_length=100)
    # We prefix each slug with the hostname of the Site, so it can be quite a bit longer than the tag's name.
    slug = models.SlugField(verbose_name='Slug', unique=True, max_length=200)

    class Meta:
        verbose_name = 'Tag'
        verbose_name_plural = 'Tags'

    def slugify(self, tag, i=None):
        """
        We override TagBase.slugify() because the 'slug' field is unique, so we need to prefix all slugs with the
        Site's hostname.
        """
        slug = "{}~{}".format(self.site.hostname, slugify(unidecode(tag)))
        if i is not None:
            slug += "_{}".format(i)
        return slug


class SiteNewsTaggedItem(TaggedItemBase):
    # Unlike the image and document *TaggedItem classes, which use a GenericForeignKey for content_object,
    # Page tags need to use a ParentalKey.
    content_object = ParentalKey('core.SiteNewsPage', related_name='tagged_pages', on_delete=models.CASCADE)
    tag = models.ForeignKey(SiteSpecificTag, related_name='%(app_label)s_%(class)s_items', on_delete=models.CASCADE)


class SiteNewsPage(Page):
    body = RichTextField()
    tags = ClusterTaggableManager(
        through=SiteNewsTaggedItem,
        blank=True,
        help_text='Enter comma-separated tags for this article. Existing tags will autocomplete as you type them.'
    )
Вернуться на верх