You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
datasketch-io/services/cms/blog/models.py

123 lines
4.5 KiB
Python

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, MultiFieldPanel
from wagtail.images.edit_handlers import ImageChooserPanel
from wagtail.search import index
class BlogIndexPage(Page):
"""Entry point of the blog. Displays its children `BlogPages`"""
intro = RichTextField(blank=True)
content_panels = Page.content_panels + [FieldPanel("intro", classname="full")]
def get_context(self, request, *args, **kwargs):
"""
Overrides the default context to include only published pages, ordered by reverse chronological order.
These child pages can be accessed in the template using `blogpages` instead of page.get_children.
"""
context = super().get_context(request)
blogpages = self.get_children().live().order_by("-first_published_at")
context["blogpages"] = blogpages
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`"""
gallery_item = self.gallery_images.first()
if gallery_item:
return gallery_item.image
else:
return None
search_fields = Page.search_fields + [
index.SearchField("intro"),
index.SearchField("body"),
]
content_panels = Page.content_panels + [
# 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"),
]
def get_context(self, request, *args, **kwargs):
context = super().get_context(request, *args, **kwargs)
context["post"] = self
return context
class BlogPageGalleryImage(Orderable):
"""
An image gallery descendant to a `BlogPage`
Inherits a `sort_order` field from the `Orderable` object which keeps track of image ordering.
The `ParentalKey` works similarly to a `ForeignKey` but also defines this class as a child of `BlogPage` model.
This means that the image gallery associated with a particular `BlogPage` instance is treated as a part of the page
in operations like submitting for moderation, and tracking version history.
The `BlogPageGalleryImage.image` is a `ForeignKey to the Wagtail built-in `Image` model where images themselves are
stored. The `ImageChooserPanel` provides a popup interface for choosing an existing image or uploading a new one.
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="+",
)
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