Search code examples
djangowagtaildjango-taggit

Filtering out private pages from tags


I recently made a tag cloud in my Wagtail-powered website, but I'm running into a problem where some tags (called "Topics" in my site) with only private articles/pages in them appear.

So far, I did something like this to get the number of articles in each tag and filter them out if there are none:

topics_with_articles = Topic.objects.annotate(num_articles=models.Count("articlepage")).filter(num_articles__gt=0)
filtered_topics = topics_with_articles.order_by("-num_articles").values("name", "slug", "num_articles")

And I have my models set up like this:

from modelcluster.models import ParentalManyToManyField, ParentalKey
from modelcluster.tags import ClusterTaggableManager
from taggit.models import Tag, TaggedItemBase

@register_snippet
class Topic(Tag):
    class Meta:
        ordering = ["slug"]
        proxy = True
        verbose_name = "Topic"
        verbose_name_plural = "Topics"

class ArticleTopic(TaggedItemBase):
    content_object = ParentalKey("ArticlePage", related_name="article_topics")

class ArticlePage(Page):
    topics = ClusterTaggableManager(through="articles.ArticleTopic", blank=True)

I couldn't find an easy solution to get this to work, so how can I do that?


Solution

  • Someone in the Wagtail Slack chat suggested this answer on taggit's undocumented most_common function, so I applied that solution something like this:

    articles = ArticlePage.objects.live().public().order_by("-date")
    topics_with_filtered_articles = ArticlePage.topics.most_common(min_count=1, extra_filters={'articlepage__in': articles})
    

    This filters out all private and draft articles out of the topics by comparing between the articles and Articles.objects queryset. By adding the min_count=1 parameter, all topics without an article are also filtered out.

    And as an added bonus, taggit made a num_times annotation in the topics_with_filtered_articles queryset so I don't have to do it myself!