From 29673c365fa95c329256ae46299b9d79f4f392e2 Mon Sep 17 00:00:00 2001 From: Jake Howard Date: Sun, 19 Jun 2022 20:55:37 +0100 Subject: [PATCH] Add tagging to blog post pages --- static/src/scss/_hero.scss | 10 +++ ...logposttag_taggedblog_blogpostpage_tags.py | 86 +++++++++++++++++++ website/blog/models.py | 31 ++++++- website/blog/wagtail_hooks.py | 14 +++ website/common/templates/common/hero.html | 7 ++ website/settings.py | 3 + 6 files changed, 150 insertions(+), 1 deletion(-) create mode 100644 website/blog/migrations/0002_blogposttag_taggedblog_blogpostpage_tags.py create mode 100644 website/blog/wagtail_hooks.py diff --git a/static/src/scss/_hero.scss b/static/src/scss/_hero.scss index 4c21191..6994cb2 100644 --- a/static/src/scss/_hero.scss +++ b/static/src/scss/_hero.scss @@ -55,4 +55,14 @@ section.hero { nav.breadcrumb { margin-bottom: 0.5rem !important; } + + .content-details { + span + span { + margin-left: 0.5rem; + } + + i { + margin-right: 5px; + } + } } diff --git a/website/blog/migrations/0002_blogposttag_taggedblog_blogpostpage_tags.py b/website/blog/migrations/0002_blogposttag_taggedblog_blogpostpage_tags.py new file mode 100644 index 0000000..5f53529 --- /dev/null +++ b/website/blog/migrations/0002_blogposttag_taggedblog_blogpostpage_tags.py @@ -0,0 +1,86 @@ +# Generated by Django 4.0.5 on 2022-06-19 19:27 + +import django.db.models.deletion +import modelcluster.contrib.taggit +import modelcluster.fields +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("blog", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="BlogPostTag", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "name", + models.CharField(max_length=100, unique=True, verbose_name="name"), + ), + ( + "slug", + models.SlugField(max_length=100, unique=True, verbose_name="slug"), + ), + ], + options={ + "verbose_name": "blog tag", + "verbose_name_plural": "blog tags", + }, + ), + migrations.CreateModel( + name="TaggedBlog", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "content_object", + modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="tagged_items", + to="blog.blogpostpage", + ), + ), + ( + "tag", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="tagged_blogs", + to="blog.blogposttag", + ), + ), + ], + options={ + "abstract": False, + }, + ), + migrations.AddField( + model_name="blogpostpage", + name="tags", + field=modelcluster.contrib.taggit.ClusterTaggableManager( + blank=True, + help_text="A comma-separated list of tags.", + through="blog.TaggedBlog", + to="blog.BlogPostTag", + verbose_name="Tags", + ), + ), + ] diff --git a/website/blog/models.py b/website/blog/models.py index 3669bc1..96fe202 100644 --- a/website/blog/models.py +++ b/website/blog/models.py @@ -1,6 +1,11 @@ from typing import Any +from django.db import models from django.http.request import HttpRequest +from modelcluster.contrib.taggit import ClusterTaggableManager +from modelcluster.fields import ParentalKey +from taggit.models import ItemBase, TagBase +from wagtail.admin.panels import FieldPanel from website.common.models import BaseContentMixin, BasePage @@ -18,7 +23,31 @@ class BlogListPage(BaseContentMixin, BasePage): # type: ignore[misc] return context +class BlogPostTag(TagBase): + free_tagging = False + + panels = [FieldPanel("name")] + + class Meta: + verbose_name = "blog tag" + verbose_name_plural = "blog tags" + + +class TaggedBlog(ItemBase): + tag = models.ForeignKey( + BlogPostTag, related_name="tagged_blogs", on_delete=models.CASCADE + ) + content_object = ParentalKey( + "blog.BlogPostPage", on_delete=models.CASCADE, related_name="tagged_items" + ) + + class BlogPostPage(BaseContentMixin, BasePage): # type: ignore[misc] subpage_types: list[Any] = [] parent_page_types = [BlogListPage] - content_panels = BasePage.content_panels + BaseContentMixin.content_panels + + tags = ClusterTaggableManager(through=TaggedBlog, blank=True) + + content_panels = ( + BasePage.content_panels + BaseContentMixin.content_panels + [FieldPanel("tags")] + ) diff --git a/website/blog/wagtail_hooks.py b/website/blog/wagtail_hooks.py new file mode 100644 index 0000000..2db5246 --- /dev/null +++ b/website/blog/wagtail_hooks.py @@ -0,0 +1,14 @@ +from wagtail.contrib.modeladmin.options import ModelAdmin, modeladmin_register + +from .models import BlogPostTag + + +class BlogPostTagModelAdmin(ModelAdmin): + model = BlogPostTag + menu_label = "Blog Post Tags" + menu_icon = "tag" + list_display = ["name", "slug"] + search_fields = ["name", "slug"] + + +modeladmin_register(BlogPostTagModelAdmin) diff --git a/website/common/templates/common/hero.html b/website/common/templates/common/hero.html index b7c9b6e..c9af2d1 100644 --- a/website/common/templates/common/hero.html +++ b/website/common/templates/common/hero.html @@ -14,6 +14,13 @@ {% if page.subtitle %}

{{ page.subtitle }}

{% endif %} +

+ 2022-04-15 + 4 minutes + {% if page.tags.all %} + {% for tag in page.tags.all %}#{{ tag.slug }}{% endfor %} + {% endif %} +