Add tagging to blog post pages
This commit is contained in:
parent
6600b9ccb7
commit
29673c365f
6 changed files with 150 additions and 1 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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",
|
||||
),
|
||||
),
|
||||
]
|
|
@ -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")]
|
||||
)
|
||||
|
|
14
website/blog/wagtail_hooks.py
Normal file
14
website/blog/wagtail_hooks.py
Normal file
|
@ -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)
|
|
@ -14,6 +14,13 @@
|
|||
{% if page.subtitle %}
|
||||
<h2 class="subtitle">{{ page.subtitle }}</h2>
|
||||
{% endif %}
|
||||
<h3 class="is-size-6 content-details">
|
||||
<span title="2022-04-15"><i class="far fa-calendar-alt"></i>2022-04-15</span>
|
||||
<span><i class="far fa-clock"></i>4 minutes</span>
|
||||
{% if page.tags.all %}
|
||||
<span class="is-family-code"><i class="fas fa-tags"></i>{% for tag in page.tags.all %}<a title="{{ tag.name }}">#{{ tag.slug }}</a>{% endfor %}</span>
|
||||
{% endif %}
|
||||
</h3>
|
||||
</div>
|
||||
<div class="column is-narrow dropdown-wrapper is-hidden-touch is-grouped">
|
||||
{% if page.table_of_contents %}
|
||||
|
|
|
@ -25,6 +25,7 @@ INSTALLED_APPS = [
|
|||
"website.blog",
|
||||
"wagtail.contrib.forms",
|
||||
"wagtail.contrib.redirects",
|
||||
"wagtail.contrib.modeladmin",
|
||||
"wagtail.embeds",
|
||||
"wagtail.sites",
|
||||
"wagtail.users",
|
||||
|
@ -136,6 +137,8 @@ WAGTAILSEARCH_BACKENDS = {
|
|||
BASE_HOSTNAME = env("BASE_HOSTNAME")
|
||||
WAGTAILADMIN_BASE_URL = f"https://{BASE_HOSTNAME}"
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||
|
||||
if DEBUG:
|
||||
# Add django-browser-reload
|
||||
INSTALLED_APPS.append("django_browser_reload")
|
||||
|
|
Loading…
Reference in a new issue