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 {
|
nav.breadcrumb {
|
||||||
margin-bottom: 0.5rem !important;
|
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 typing import Any
|
||||||
|
|
||||||
|
from django.db import models
|
||||||
from django.http.request import HttpRequest
|
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
|
from website.common.models import BaseContentMixin, BasePage
|
||||||
|
|
||||||
|
@ -18,7 +23,31 @@ class BlogListPage(BaseContentMixin, BasePage): # type: ignore[misc]
|
||||||
return context
|
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]
|
class BlogPostPage(BaseContentMixin, BasePage): # type: ignore[misc]
|
||||||
subpage_types: list[Any] = []
|
subpage_types: list[Any] = []
|
||||||
parent_page_types = [BlogListPage]
|
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 %}
|
{% if page.subtitle %}
|
||||||
<h2 class="subtitle">{{ page.subtitle }}</h2>
|
<h2 class="subtitle">{{ page.subtitle }}</h2>
|
||||||
{% endif %}
|
{% 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>
|
||||||
<div class="column is-narrow dropdown-wrapper is-hidden-touch is-grouped">
|
<div class="column is-narrow dropdown-wrapper is-hidden-touch is-grouped">
|
||||||
{% if page.table_of_contents %}
|
{% if page.table_of_contents %}
|
||||||
|
|
|
@ -25,6 +25,7 @@ INSTALLED_APPS = [
|
||||||
"website.blog",
|
"website.blog",
|
||||||
"wagtail.contrib.forms",
|
"wagtail.contrib.forms",
|
||||||
"wagtail.contrib.redirects",
|
"wagtail.contrib.redirects",
|
||||||
|
"wagtail.contrib.modeladmin",
|
||||||
"wagtail.embeds",
|
"wagtail.embeds",
|
||||||
"wagtail.sites",
|
"wagtail.sites",
|
||||||
"wagtail.users",
|
"wagtail.users",
|
||||||
|
@ -136,6 +137,8 @@ WAGTAILSEARCH_BACKENDS = {
|
||||||
BASE_HOSTNAME = env("BASE_HOSTNAME")
|
BASE_HOSTNAME = env("BASE_HOSTNAME")
|
||||||
WAGTAILADMIN_BASE_URL = f"https://{BASE_HOSTNAME}"
|
WAGTAILADMIN_BASE_URL = f"https://{BASE_HOSTNAME}"
|
||||||
|
|
||||||
|
DEFAULT_AUTO_FIELD = "django.db.models.AutoField"
|
||||||
|
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
# Add django-browser-reload
|
# Add django-browser-reload
|
||||||
INSTALLED_APPS.append("django_browser_reload")
|
INSTALLED_APPS.append("django_browser_reload")
|
||||||
|
|
Loading…
Reference in a new issue