From 089af2cd13ff5b43219fd79e2cce1ead7df9c25f Mon Sep 17 00:00:00 2001
From: Jordan Robinson
Date: Wed, 24 Sep 2025 21:50:22 +0100
Subject: [PATCH] add all_tags lists to templates and postmanager functions to
get all unique tags for posts and blog setting to show/hide tags in posts
list
---
main/admin.py | 1 +
..._show_tags_in_post_list_alter_post_tags.py | 23 +++++++++++++
main/models.py | 34 +++++++++++++++++++
main/templates/main/blog_posts.html | 11 +++++-
main/templates/main/post_list.html | 12 ++++++-
main/urls.py | 1 +
main/views/general.py | 22 ++++++++++--
7 files changed, 100 insertions(+), 4 deletions(-)
create mode 100644 main/migrations/0122_user_show_tags_in_post_list_alter_post_tags.py
diff --git a/main/admin.py b/main/admin.py
index 33a89b17d21c6a69039ce0f587f456d2c861841e..0b9fb0d7bdb6ff783912bc8487f14d43eb7d91d4 100644
--- a/main/admin.py
+++ b/main/admin.py
@@ -60,6 +60,7 @@ class UserAdmin(DjUserAdmin):
"post_backups_on",
"show_posts_on_homepage",
"show_posts_in_nav",
+ "show_tags_in_post_list",
"noindex_on",
"reading_time_on",
"export_unsubscribe_key",
diff --git a/main/migrations/0122_user_show_tags_in_post_list_alter_post_tags.py b/main/migrations/0122_user_show_tags_in_post_list_alter_post_tags.py
new file mode 100644
index 0000000000000000000000000000000000000000..1f83c3b53a6a25e007d0f07c2fd48bac2d0935d6
--- /dev/null
+++ b/main/migrations/0122_user_show_tags_in_post_list_alter_post_tags.py
@@ -0,0 +1,23 @@
+# Generated by Django 5.2.5 on 2025-09-24 20:42
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('main', '0121_post_tags'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='user',
+ name='show_tags_in_post_list',
+ field=models.BooleanField(default=True, help_text='Show/hide tags in the post list.', verbose_name='Show Tags In Post List'),
+ ),
+ migrations.AlterField(
+ model_name='post',
+ name='tags',
+ field=models.CharField(blank=True, default=None, help_text='Enter comma-separated tags (e.g., django, python, blog).', max_length=300, null=True),
+ ),
+ ]
diff --git a/main/models.py b/main/models.py
index 626f6311430c9ff9994570ab20851f2fb96205c9..fda52dc330feba435f2668b023a0538d6105fa7a 100644
--- a/main/models.py
+++ b/main/models.py
@@ -2,6 +2,8 @@ import base64
import binascii
import os
import uuid
+import re
+from django.db.models import Q
import bleach
from django.conf import settings
@@ -17,6 +19,31 @@ def _generate_key():
"""Return 32-char random string."""
return binascii.b2a_hex(os.urandom(16)).decode("utf-8")
+# custom queryset and manager for Post model to handle tag operations
+
+class PostQuerySet(models.QuerySet):
+ def with_tag(self, tag):
+ return self.filter(
+ Q(tags__regex=rf'(^|,){re.escape(tag)}(,|$)')
+ )
+
+ def all_unique_tags(self):
+ tags = set()
+ for post in self.exclude(tags__isnull=True).exclude(tags=""):
+ for tag in post.tag_list:
+ tags.add(tag)
+ return sorted(tags)
+
+class PostManager(models.Manager):
+ def get_queryset(self):
+ return PostQuerySet(self.model, using=self._db)
+
+ def with_tag(self, tag):
+ return self.get_queryset().with_tag(tag)
+
+ def all_unique_tags(self):
+ return self.get_queryset().all_unique_tags()
+
class User(AbstractUser):
username = models.CharField(
@@ -117,6 +144,11 @@ class User(AbstractUser):
help_text="Show/hide posts in the navigation bar.",
verbose_name="Show Posts In Nav",
)
+ show_tags_in_post_list = models.BooleanField(
+ default=True,
+ help_text="Show/hide tags in the post list.",
+ verbose_name="Show Tags In Post List",
+ )
noindex_on = models.BooleanField(
default=False,
help_text="Add a noindex meta tag so your blog is not indexed by search engines.",
@@ -270,6 +302,8 @@ class Post(models.Model):
ordering = ["-published_at", "-created_at"]
unique_together = [["slug", "owner"]]
+ objects = PostManager()
+
@property
def body_as_html(self):
return util.md_to_html(self.body)
diff --git a/main/templates/main/blog_posts.html b/main/templates/main/blog_posts.html
index ff1cf18afcb8ed4009cb22ceb46fe5b1f4a41221..308884fda6766e957758b42979ca8fb483ad4570 100644
--- a/main/templates/main/blog_posts.html
+++ b/main/templates/main/blog_posts.html
@@ -69,7 +69,7 @@
{% if p.published_at %}
{{ p.title }}
- {% if p.tag_list %}
+ {% if p.tag_list and request.user.show_tags_in_post_list %}
—
Tags:
@@ -91,6 +91,15 @@
{% endif %}
{% endfor %}
+
+ {% if all_tags and request.user.show_tags_in_post_list %}
+
+ All tags:
+ {% for tag in all_tags %}
+ {{ tag }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+
+ {% endif %}
diff --git a/main/templates/main/post_list.html b/main/templates/main/post_list.html
index d19b84d9c768581351cbead4ac64a0a8b2b9a8b1..ca4b268f601fb796a4781e4c44fbac98413ce658 100644
--- a/main/templates/main/post_list.html
+++ b/main/templates/main/post_list.html
@@ -14,6 +14,7 @@
Active tag filter: {{ filter_tag }} (clear filter)
{% endif %}
+
List of posts:
@@ -23,7 +24,7 @@
{{ post.title }}
- {% if p.tag_list %}
+ {% if p.tag_list and request.user.show_tags_in_post_list %}
—
Tags:
@@ -48,5 +49,14 @@
{% endfor %}
{% endif %}
+
+ {% if all_tags and request.user.show_tags_in_post_list %}
+
+ All tags:
+ {% for tag in all_tags %}
+ {{ tag }}{% if not forloop.last %}, {% endif %}
+ {% endfor %}
+
+ {% endif %}
{% endblock content %}
diff --git a/main/urls.py b/main/urls.py
index d07315e835e1ae3f0a596935f80771e9fa263bc3..fcfa5d98f21df27755cb4291ba630486772ba222 100644
--- a/main/urls.py
+++ b/main/urls.py
@@ -80,6 +80,7 @@ urlpatterns += [
# blog posts and post snapshots
urlpatterns += [
path("posts-workshop/", general.PostList.as_view(), name="post_list_dashboard"),
+ path("posts-workshop/tag//", general.PostList.as_view(), name="post_list_dashboard_filter"),
path(
"post-backups/create/", general.SnapshotCreate.as_view(), name="snapshot_create"
),
diff --git a/main/views/general.py b/main/views/general.py
index 6f2ffcbf71dd67d1abc890e4f84eaa18dd34bb43..bead95ecf043b9740a0c98609b348022f5e5b0f2 100644
--- a/main/views/general.py
+++ b/main/views/general.py
@@ -152,7 +152,8 @@ def post_list(request):
"pages": models.Page.objects.filter(
owner=request.blog_user, is_hidden=False
).defer("body"),
- "license_url": license_url
+ "license_url": license_url,
+ "all_tags": models.Post.objects.all_unique_tags()
},
)
@@ -207,6 +208,7 @@ def post_list_filter(request, tag = None):
).defer("body"),
"license_url": license_url,
"filter_tag": tag,
+ "all_tags": models.Post.objects.all_unique_tags()
},
)
@@ -228,7 +230,22 @@ class PostList(LoginRequiredMixin, ListView):
model = models.Post
def get_queryset(self):
- return models.Post.objects.filter(owner=self.request.user)
+ qs = models.Post.objects.filter(owner=self.request.user)
+
+ #tag = self.request.GET.get("tag")
+ tag = self.kwargs.get("tag")
+ if tag:
+ qs = qs.with_tag(tag)
+
+ return qs
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+ context["filter_tag"] = self.kwargs.get("tag")
+ context["all_tags"] = models.Post.objects.filter(
+ owner=self.request.user
+ ).all_unique_tags()
+ return context
def domain_check(request):
"""
@@ -335,6 +352,7 @@ class UserUpdate(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
"post_backups_on",
"show_posts_on_homepage",
"show_posts_in_nav",
+ "show_tags_in_post_list",
"noindex_on",
"reading_time_on",
"robots_txt",