From 5832137a342d8b0d35c1503be72d96492f4d56bb Mon Sep 17 00:00:00 2001 From: androiddrew Date: Mon, 19 Nov 2018 15:18:00 -0500 Subject: [PATCH] Added basic tagging to blog posts --- .../migrations/0003_blogpagegalleryimage.py | 48 +++++++++++---- .../migrations/0004_auto_20181119_1950.py | 33 ++++++++++ .../blog/migrations/0005_blogtagindexpage.py | 25 ++++++++ services/cms/blog/models.py | 44 +++++++++++++- .../blog/templates/blog/blog_index_page.html | 52 ++++++++-------- .../cms/blog/templates/blog/blog_page.html | 39 ++++++++---- .../templates/blog/blog_tag_index_page.html | 38 ++++++++++++ services/cms/cms/templates/404.html | 4 +- services/cms/cms/templates/500.html | 18 +++--- services/cms/cms/templates/base.html | 60 +++++++++---------- 10 files changed, 265 insertions(+), 96 deletions(-) create mode 100644 services/cms/blog/migrations/0004_auto_20181119_1950.py create mode 100644 services/cms/blog/migrations/0005_blogtagindexpage.py create mode 100644 services/cms/blog/templates/blog/blog_tag_index_page.html diff --git a/services/cms/blog/migrations/0003_blogpagegalleryimage.py b/services/cms/blog/migrations/0003_blogpagegalleryimage.py index 896a436..a34d198 100644 --- a/services/cms/blog/migrations/0003_blogpagegalleryimage.py +++ b/services/cms/blog/migrations/0003_blogpagegalleryimage.py @@ -8,23 +8,45 @@ import modelcluster.fields class Migration(migrations.Migration): dependencies = [ - ('wagtailimages', '0021_image_file_hash'), - ('blog', '0002_blogpage'), + ("wagtailimages", "0021_image_file_hash"), + ("blog", "0002_blogpage"), ] operations = [ migrations.CreateModel( - name='BlogPageGalleryImage', + name="BlogPageGalleryImage", fields=[ - ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('sort_order', models.IntegerField(blank=True, editable=False, null=True)), - ('caption', models.CharField(blank=True, max_length=250)), - ('image', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='+', to='wagtailimages.Image')), - ('page', modelcluster.fields.ParentalKey(on_delete=django.db.models.deletion.CASCADE, related_name='gallery_images', to='blog.BlogPage')), + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ( + "sort_order", + models.IntegerField(blank=True, editable=False, null=True), + ), + ("caption", models.CharField(blank=True, max_length=250)), + ( + "image", + models.ForeignKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="+", + to="wagtailimages.Image", + ), + ), + ( + "page", + modelcluster.fields.ParentalKey( + on_delete=django.db.models.deletion.CASCADE, + related_name="gallery_images", + to="blog.BlogPage", + ), + ), ], - options={ - 'ordering': ['sort_order'], - 'abstract': False, - }, - ), + options={"ordering": ["sort_order"], "abstract": False}, + ) ] diff --git a/services/cms/blog/migrations/0004_auto_20181119_1950.py b/services/cms/blog/migrations/0004_auto_20181119_1950.py new file mode 100644 index 0000000..8263194 --- /dev/null +++ b/services/cms/blog/migrations/0004_auto_20181119_1950.py @@ -0,0 +1,33 @@ +# Generated by Django 2.1.2 on 2018-11-19 19:50 + +from django.db import migrations, models +import django.db.models.deletion +import modelcluster.contrib.taggit +import modelcluster.fields + + +class Migration(migrations.Migration): + + dependencies = [ + ('taggit', '0002_auto_20150616_2121'), + ('blog', '0003_blogpagegalleryimage'), + ] + + operations = [ + migrations.CreateModel( + name='BlogPageTag', + 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.BlogPage')), + ('tag', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='blog_blogpagetag_items', to='taggit.Tag')), + ], + options={ + 'abstract': False, + }, + ), + migrations.AddField( + model_name='blogpage', + name='tags', + field=modelcluster.contrib.taggit.ClusterTaggableManager(blank=True, help_text='A comma-separated list of tags.', through='blog.BlogPageTag', to='taggit.Tag', verbose_name='Tags'), + ), + ] diff --git a/services/cms/blog/migrations/0005_blogtagindexpage.py b/services/cms/blog/migrations/0005_blogtagindexpage.py new file mode 100644 index 0000000..8fea19f --- /dev/null +++ b/services/cms/blog/migrations/0005_blogtagindexpage.py @@ -0,0 +1,25 @@ +# Generated by Django 2.1.2 on 2018-11-19 20:04 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('wagtailcore', '0040_page_draft_title'), + ('blog', '0004_auto_20181119_1950'), + ] + + operations = [ + migrations.CreateModel( + name='BlogTagIndexPage', + fields=[ + ('page_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='wagtailcore.Page')), + ], + options={ + 'abstract': False, + }, + bases=('wagtailcore.page',), + ), + ] diff --git a/services/cms/blog/models.py b/services/cms/blog/models.py index 2486cda..139cea0 100644 --- a/services/cms/blog/models.py +++ b/services/cms/blog/models.py @@ -1,10 +1,12 @@ from django.db import models from modelcluster.fields import ParentalKey +from modelcluster.contrib.taggit import ClusterTaggableManager +from taggit.models import TaggedItemBase from wagtail.core.models import Page, Orderable from wagtail.core.fields import RichTextField -from wagtail.admin.edit_handlers import FieldPanel, InlinePanel +from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, MultiFieldPanel from wagtail.images.edit_handlers import ImageChooserPanel from wagtail.search import index @@ -27,10 +29,21 @@ class BlogIndexPage(Page): return context +class BlogPageTag(TaggedItemBase): + """Provides a simple tagging feature to Blog Pages""" + + content_object = ParentalKey( + "BlogPage", related_name="tagged_items", on_delete=models.CASCADE + ) + + class BlogPage(Page): + """Models a blog page entry.""" + date = models.DateField("Post date") intro = models.CharField(max_length=250) body = RichTextField(blank=True) + tags = ClusterTaggableManager(through=BlogPageTag, blank=True) def main_image(self): """Returns the first image associated with a `BlogPage` from `BlogPageGalleryImage`""" @@ -46,7 +59,10 @@ class BlogPage(Page): ] content_panels = Page.content_panels + [ - FieldPanel("date"), + # Grouping Date and tags together for readability in the Admin panel + MultiFieldPanel( + [FieldPanel("date"), FieldPanel("tags")], heading="Blog information" + ), FieldPanel("intro"), FieldPanel("body", classname="full"), InlinePanel("gallery_images", label="Gallery images"), @@ -67,13 +83,35 @@ class BlogPageGalleryImage(Orderable): This allows for the same image to exist in multiple galleries - effectively creating a many-to-many relationship between pages and images. """ + page = ParentalKey( BlogPage, on_delete=models.CASCADE, related_name="gallery_images" ) image = models.ForeignKey( # on_delete here means that is an image is deleted from the system, the gallery entry is deleted as well. - "wagtailimages.Image", on_delete=models.CASCADE, related_name="+" + "wagtailimages.Image", + on_delete=models.CASCADE, + related_name="+", ) caption = models.CharField(blank=True, max_length=250) panels = [ImageChooserPanel("image"), FieldPanel("caption")] + + +class BlogTagIndexPage(Page): + """ + Models the Index page of blogs by tag. + + Even though this model does not define any fields of its own, it is a subclass of Page and is added to the Wagtail + ecosystem. This means that it can be given a title and a URL in the admin + + """ + + def get_context(self, request, *args, **kwargs): + """Filters by tage passed in request query string""" + tag = request.GET.get('tag') + blogpages = BlogPage.objects.filter(tags__name=tag) + + context = super().get_context(request) + context['blogpages'] = blogpages + return context \ No newline at end of file diff --git a/services/cms/blog/templates/blog/blog_index_page.html b/services/cms/blog/templates/blog/blog_index_page.html index 45454f8..1d06c27 100644 --- a/services/cms/blog/templates/blog/blog_index_page.html +++ b/services/cms/blog/templates/blog/blog_index_page.html @@ -1,4 +1,4 @@ -{% extends "base.html" %} +{% extends "base.html" %} {% load wagtailcore_tags wagtailimages_tags %} @@ -6,32 +6,32 @@ {% block content %} -
-

{{ page.title }}

- - {% for post in blogpages %} - {% with post=post.specific %} -
- -
- {% endwith %} - {% endfor %} - -
+

By {{ post.owner }}

+ + + + {% endwith %} + {% endfor %} + + {% endblock %} diff --git a/services/cms/blog/templates/blog/blog_page.html b/services/cms/blog/templates/blog/blog_page.html index 5469e85..7c4db58 100644 --- a/services/cms/blog/templates/blog/blog_page.html +++ b/services/cms/blog/templates/blog/blog_page.html @@ -5,17 +5,30 @@ {% block body_class %}helvetica{% endblock %} {% block content %} -

{{ page.title }}

-

{{ page.date }}

- -
{{ page.intro }}
- {{ page.body|richtext }} - - {% for item in page.gallery_images.all %} -
- {% image item.image fill-320x240 %} -

{{ item.caption }}

-
- {% endfor %} -

Return to blog

+

{{ page.title }}

+

{{ page.date }}

+ +
{{ page.intro }}
+ {{ page.body|richtext }} + + {% for item in page.gallery_images.all %} +
+ {% image item.image fill-320x240 %} +

{{ item.caption }}

+
+ {% endfor %} + + {% if page.tags.all.count %} +
+

Tags

+ {% for tag in page.tags.all %} + + + + {% endfor %} +
+ + {% endif %} + +

Return to blog

{% endblock %} \ No newline at end of file diff --git a/services/cms/blog/templates/blog/blog_tag_index_page.html b/services/cms/blog/templates/blog/blog_tag_index_page.html new file mode 100644 index 0000000..a9c4c16 --- /dev/null +++ b/services/cms/blog/templates/blog/blog_tag_index_page.html @@ -0,0 +1,38 @@ +{% extends "base.html" %} +{% load wagtailcore_tags wagtailimages_tags %} + +{% block body_class %}helvetica{% endblock %} + +{% block content %} + +
+ {% if request.GET.tag|length %} +

Showing pages tagged "{{ request.GET.tag }}"

+ {% endif %} + + {% for post in blogpages %} + {% with post=post.specific %} + + {% endwith %} + {% empty %} + No pages found with that tag. + {% endfor %} +
+ +{% endblock %} \ No newline at end of file diff --git a/services/cms/cms/templates/404.html b/services/cms/cms/templates/404.html index 3a5500e..e119fa8 100644 --- a/services/cms/cms/templates/404.html +++ b/services/cms/cms/templates/404.html @@ -3,7 +3,7 @@ {% block body_class %}template-404{% endblock %} {% block content %} -

Page not found

+

Page not found

-

Sorry, this page could not be found.

+

Sorry, this page could not be found.

{% endblock %} diff --git a/services/cms/cms/templates/500.html b/services/cms/cms/templates/500.html index 72b6406..c7248dd 100644 --- a/services/cms/cms/templates/500.html +++ b/services/cms/cms/templates/500.html @@ -1,13 +1,13 @@ - - - Internal server error - - - -

Internal server error

+ + + Internal server error + + + +

Internal server error

-

Sorry, there seems to be an error. Please try again soon.

- +

Sorry, there seems to be an error. Please try again soon.

+ diff --git a/services/cms/cms/templates/base.html b/services/cms/cms/templates/base.html index 87ed833..af3e1ea 100644 --- a/services/cms/cms/templates/base.html +++ b/services/cms/cms/templates/base.html @@ -2,40 +2,40 @@ - - - - {% block title %} - {% if self.seo_title %}{{ self.seo_title }}{% else %}{{ self.title }}{% endif %} - {% endblock %} - {% block title_suffix %} - {% with self.get_site.site_name as site_name %} - {% if site_name %}- {{ site_name }}{% endif %} - {% endwith %} - {% endblock %} - - - + + + + {% block title %} + {% if self.seo_title %}{{ self.seo_title }}{% else %}{{ self.title }}{% endif %} + {% endblock %} + {% block title_suffix %} + {% with self.get_site.site_name as site_name %} + {% if site_name %}- {{ site_name }}{% endif %} + {% endwith %} + {% endblock %} + + + - {# Global stylesheets #} - - + {# Global stylesheets #} + + - {% block extra_css %} - {# Override this in templates to add extra stylesheets #} - {% endblock %} - + {% block extra_css %} + {# Override this in templates to add extra stylesheets #} + {% endblock %} + - - {% wagtailuserbar %} + +{% wagtailuserbar %} - {% block content %}{% endblock %} +{% block content %}{% endblock %} - {# Global javascript #} - +{# Global javascript #} + - {% block extra_js %} - {# Override this in templates to add extra javascript #} - {% endblock %} - +{% block extra_js %} + {# Override this in templates to add extra javascript #} +{% endblock %} +