iamkonstantin/blog/models.py

157 lines
4.3 KiB
Python

from typing import Optional
from django import forms
from django.db import models
from modelcluster.fields import ParentalKey, ParentalManyToManyField
from modelcluster.contrib.taggit import ClusterTaggableManager
from taggit.models import TaggedItemBase
from wagtail.api import APIField
from wagtail.images.api.fields import ImageRenditionField
from wagtail.models import Page, Orderable
from wagtail.fields import RichTextField, StreamField
from wagtail.admin.panels import FieldPanel, InlinePanel, MultiFieldPanel
from wagtail.search import index
from wagtail.snippets.models import register_snippet
from blog.blocks import BlogPostBlock
from wagtailseo.models import SeoMixin, SeoType
class BlogIndexPage(SeoMixin, Page):
intro = RichTextField(blank=True)
def get_context(self, request):
# Update context to include only published posts, ordered by reverse-chron
context = super().get_context(request)
blogpages = self.get_children().live().order_by('-first_published_at')
context['blogpages'] = blogpages
return context
content_panels = Page.content_panels + [
FieldPanel('intro')
]
promote_panels = SeoMixin.seo_panels
class BlogTagIndexPage(Page):
def get_context(self, request):
tag = request.GET.get('tag')
blogpages = BlogPage.objects.live().filter(tags__name=tag).order_by('-first_published_at')
# Update template context
context = super().get_context(request)
context['blogpages'] = blogpages
return context
class BlogPageTag(TaggedItemBase):
content_object = ParentalKey(
'BlogPage',
related_name='tagged_items',
on_delete=models.CASCADE
)
class BlogPage(SeoMixin, Page):
date = models.DateField("Post date")
intro = models.TextField()
body = StreamField(
BlogPostBlock(),
blank=True,
use_json_field=True,
help_text="Write anything",
)
authors = ParentalManyToManyField('blog.Author', blank=True)
tags = ClusterTaggableManager(through=BlogPageTag, blank=True)
def main_image(self):
gallery_item = self.gallery_images.first()
if gallery_item:
return gallery_item.image
else:
return None
# Export fields over the API
api_fields = [
APIField('gallery_images'),
# Adds a URL to a rendered thumbnail of the image to the API
APIField('body'),
APIField('intro'),
APIField('tags'),
]
search_fields = Page.search_fields + [
index.SearchField('intro'),
index.SearchField('body'),
]
content_panels = Page.content_panels + [
MultiFieldPanel([
FieldPanel('date'),
FieldPanel('authors', widget=forms.CheckboxSelectMultiple),
FieldPanel('tags'),
], heading="Blog information"),
FieldPanel('intro'),
FieldPanel('body'),
InlinePanel('gallery_images', label="Gallery images"),
]
settings_panels = Page.settings_panels = [
FieldPanel('first_published_at')
]
promote_panels = SeoMixin.seo_panels
seo_content_type = SeoType.ARTICLE
@property
def seo_author(self) -> str:
return ', '.join([author.name for author in self.authors.all()])
@property
def seo_canonical_url(self) -> str:
# replace http:// with https://
return super().seo_canonical_url.replace('http://', 'https://')
@property
def seo_struct_publisher_dict(self) -> Optional[dict]:
return None
class BlogPageGalleryImage(Orderable):
page = ParentalKey(BlogPage, on_delete=models.CASCADE, related_name='gallery_images')
image = models.ForeignKey(
'wagtailimages.Image', on_delete=models.CASCADE, related_name='+'
)
caption = models.CharField(blank=True, max_length=250)
panels = [
FieldPanel('image'),
FieldPanel('caption'),
]
api_fields = [
APIField('image'),
]
@register_snippet
class Author(models.Model):
name = models.CharField(max_length=255)
author_image = models.ForeignKey(
'wagtailimages.Image', null=True, blank=True,
on_delete=models.SET_NULL, related_name='+'
)
panels = [
FieldPanel('name'),
FieldPanel('author_image'),
]
def __str__(self):
return self.name
class Meta:
verbose_name_plural = 'Authors'