Skip to content

Commit

Permalink
Improve blog
Browse files Browse the repository at this point in the history
  • Loading branch information
Ash-Crow committed Feb 15, 2024
1 parent 3488b43 commit 7e836d7
Show file tree
Hide file tree
Showing 17 changed files with 805 additions and 342 deletions.
18 changes: 18 additions & 0 deletions blog/migrations/0003_blogentrypage_date.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-02-13 14:30

import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("blog", "0002_blogentrypage_blog_categories_blogentrypage_tags_and_more"),
]

operations = [
migrations.AddField(
model_name="blogentrypage",
name="date",
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name="Post date"),
),
]
26 changes: 26 additions & 0 deletions blog/migrations/0004_blogentrypage_header_image.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 5.0.2 on 2024-02-13 14:40

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("blog", "0003_blogentrypage_date"),
("wagtailimages", "0025_alter_image_file_alter_rendition_file"),
]

operations = [
migrations.AddField(
model_name="blogentrypage",
name="header_image",
field=models.ForeignKey(
blank=True,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to="wagtailimages.image",
verbose_name="Header image",
),
),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# Generated by Django 5.0.2 on 2024-02-14 14:04

import uuid

import django.db.models.deletion
from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("blog", "0004_blogentrypage_header_image"),
("wagtailcore", "0091_remove_revision_submitted_for_moderation"),
]

operations = [
migrations.AddField(
model_name="category",
name="locale",
field=models.ForeignKey(
default=1,
editable=False,
on_delete=django.db.models.deletion.PROTECT,
related_name="+",
to="wagtailcore.locale",
),
preserve_default=False,
),
migrations.AddField(
model_name="category",
name="translation_key",
field=models.UUIDField(default=uuid.uuid4, editable=False),
),
migrations.AlterUniqueTogether(
name="category",
unique_together={("name", "locale"), ("slug", "locale"), ("translation_key", "locale")},
),
]
130 changes: 125 additions & 5 deletions blog/models.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,21 @@
from django.core.exceptions import ValidationError
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.db import models
from django.db.models import Count
from django.db.models.expressions import F
from django.shortcuts import get_object_or_404
from django.template.defaultfilters import slugify
from django.utils.translation import gettext_lazy as _
from django.utils import timezone
from django.utils.translation import get_language, gettext_lazy as _
from modelcluster.fields import ParentalKey
from modelcluster.tags import ClusterTaggableManager
from taggit.models import Tag as TaggitTag, TaggedItemBase
from wagtail.admin.panels import FieldPanel, MultiFieldPanel, TitleFieldPanel
from wagtail.admin.panels import FieldPanel, FieldRowPanel, MultiFieldPanel, TitleFieldPanel
from wagtail.admin.widgets.slug import SlugInput
from wagtail.fields import StreamField
from wagtail.images import get_image_model_string
from wagtail.models import Page
from wagtail.models.i18n import Locale, TranslatableMixin
from wagtail.search import index
from wagtail.snippets.models import register_snippet

Expand All @@ -28,45 +35,153 @@ class BlogIndexPage(Page):
class Meta:
verbose_name = _("Blog index")

@property
def posts(self):
# Get list of blog pages that are descendants of this page
posts = BlogEntryPage.objects.descendant_of(self).live()
posts = (
posts.order_by("-date").select_related("owner").prefetch_related("tags", "blog_categories", "date__year")
)
return posts

def get_context(self, request, tag=None, category=None, author=None, year=None, *args, **kwargs): # NOSONAR
context = super(BlogIndexPage, self).get_context(request, *args, **kwargs)
posts = self.posts
locale = Locale.objects.get(language_code=get_language())

if tag is None:
tag = request.GET.get("tag")
if tag:
posts = posts.filter(tags__slug=tag)
if category is None: # Not coming from category_view in views.py
if request.GET.get("category"):
category = get_object_or_404(
Category,
slug=request.GET.get("category"),
locale=locale,
)
if category:
if not request.GET.get("category"):
category = get_object_or_404(Category, slug=category, locale=locale)
posts = posts.filter(blog_categories__slug=category.slug)
if author:
if isinstance(author, str) and not author.isdigit():
posts = posts.filter(author__username=author)
else:
posts = posts.filter(author_id=author)

if year:
posts = posts.filter(date__year=year)

# Pagination
page = request.GET.get("page")
page_size = 10

paginator = Paginator(posts, page_size) # Show 10 posts per page
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)

context["posts"] = posts
if category is not None:
context["category"] = category.name
context["tag"] = tag
context["author"] = author
context["year"] = year
context["paginator"] = paginator

return context

def list_categories(self) -> list:
posts = self.posts.specific()
return (
posts.values(
cat_slug=F("blog_categories__slug"),
cat_name=F("blog_categories__name"),
)
.annotate(cat_count=Count("cat_slug"))
.filter(cat_count__gte=1)
.order_by("-cat_count")
)

def list_tags(self, min_count: int = 1) -> list:
posts = self.posts.specific()
return (
posts.values(tag_name=F("tags__name"), tag_slug=F("tags__slug"))
.annotate(tag_count=Count("tag_slug"))
.filter(tag_count__gte=min_count)
.order_by("-tag_count")
)


class BlogEntryPage(Page):
body = StreamField(
STREAMFIELD_COMMON_FIELDS,
blank=True,
use_json_field=True,
)

header_image = models.ForeignKey(
get_image_model_string(),
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name="+",
verbose_name=_("Header image"),
)
tags = ClusterTaggableManager(through="TagEntryPage", blank=True)
blog_categories = models.ManyToManyField(
"Category",
through="CategoryEntryPage",
blank=True,
verbose_name=_("Categories"),
)
date = models.DateTimeField(verbose_name=_("Post date"), default=timezone.now)

parent_page_types = ["blog.BlogIndexPage"]
subpage_types = []

content_panels = Page.content_panels + [
FieldPanel("header_image"),
FieldPanel("body", heading=_("body")),
]

settings_panels = Page.settings_panels + [
FieldPanel("owner", heading=_("Author")),
FieldPanel("date"),
MultiFieldPanel(
[
FieldRowPanel(
[
FieldPanel("go_live_at"),
FieldPanel("expire_at"),
],
classname="label-above",
),
],
_("Scheduled publishing"),
classname="publishing",
),
MultiFieldPanel(
[
FieldPanel("tags"),
FieldPanel("blog_categories"),
FieldPanel("tags"),
],
heading=_("Tags and Categories"),
),
]

def get_absolute_url(self):
return self.url

class Meta:
verbose_name = _("Blog page")


@register_snippet
class Category(index.Indexed, models.Model):
class Category(TranslatableMixin, index.Indexed, models.Model):
name = models.CharField(max_length=80, unique=True, verbose_name=_("Category name"))
slug = models.SlugField(unique=True, max_length=80)
parent = models.ForeignKey(
Expand Down Expand Up @@ -108,6 +223,11 @@ class Meta:
ordering = ["name"]
verbose_name = _("Category")
verbose_name_plural = _("Categories")
unique_together = [
("translation_key", "locale"),
("name", "locale"),
("slug", "locale"),
]

search_fields = [index.SearchField("name")]

Expand Down
47 changes: 21 additions & 26 deletions blog/templates/blog/blog_entry_page.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,39 +13,25 @@
{% endif %}

{% block content %}
{# Display Django message info from previous form #}
{% if messages %}
<div class="fr-container fr-mt-6w">
<div class="fr-grid-row fr-grid-row--gutters">
<div class="fr-col-12">
{% for message in messages %}
{% if message.tags == "success" %}
<div class="fr-alert fr-alert--success fr-alert--sm fr-mb-5w"
role="status">
<p>{{ message }}</p>
</div>
{% elif message.tags == "info" %}
<div class="fr-alert fr-alert--info fr-alert--sm fr-mb-5w" role="status">
<p>{{ message }}</p>
</div>
{% elif message.tags == "error" %}
<div class="fr-alert fr-alert--error fr-alert--sm fr-mb-5w" role="alert">
<p>{{ message }}</p>
</div>
{% endif %}
{% endfor %}
</div>
</div>
</div>
{% endif %}
{% include "content_manager/blocks/messages.html" %}

<div class="fr-container fr-mt-6w">
<div class="fr-grid-row fr-grid-row--gutters">
<div class="fr-col-12{% if not block.value.large %} fr-col-offset-md-2 fr-col-md-8{% endif %}">
<div class="fr-col-12">
{% include "content_manager/blocks/breadcrumbs.html" %}
<h1 class="fr-display--sm">{{ page.title }}</h1>
</div>
</div>
<p>
Publié le {{ page.date |date:'Y-m-d H:i:s e' }}
{% if page.blog_categories.all %}
|
{% for category in page.blog_categories.all %}
<a href="{% url 'blog:category' page.get_parent.slug category.slug %}">{{ category.name }}</a>
{% if not forloop.last %},{% endif %}
{% endfor %}
{% endif %}
</p>
</div>

{% for block in page.body %}
Expand Down Expand Up @@ -102,4 +88,13 @@ <h1 class="fr-display--sm">{{ page.title }}</h1>
</div>
{% endif %}
{% endfor %}

<div class="fr-container fr-my-6w">
{% for tag in page.tags.all|dictsort:"slug" %}
<a class="fr-tag"
target="_self"
href="{% url 'blog:tag' page.get_parent.slug tag.slug %}">{{ tag }}</a>
{% endfor %}
</div>

{% endblock content %}
Loading

0 comments on commit 7e836d7

Please sign in to comment.