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",