Fixes: None. Extra: Update `django.po` and `django.mo` localization files to reflect translation changes and model updates.
138 lines
5.2 KiB
Python
138 lines
5.2 KiB
Python
from django.db.models import CASCADE, CharField, FileField, ForeignKey, ManyToManyField
|
|
from django.utils.translation import gettext_lazy as _
|
|
from django_extensions.db.fields import AutoSlugField
|
|
from markdown.extensions.toc import TocExtension
|
|
from markdown_field import MarkdownField
|
|
|
|
from core.abstract import NiceModel
|
|
|
|
|
|
class Post(NiceModel): # type: ignore [django-manager-missing]
|
|
"""
|
|
Represents a blog post model extending NiceModel.
|
|
|
|
The Post class defines the structure and behavior of a blog post. It includes
|
|
attributes for author, title, content, optional file attachment, slug,
|
|
and associated tags. The class enforces constraints such as requiring either
|
|
content or a file attachment but not both simultaneously. It also supports
|
|
automatic slug generation based on the title. This model can be used in
|
|
a blogging platform to manage posts created by users.
|
|
|
|
Attributes:
|
|
is_publicly_visible (bool): Specifies whether the post is visible to the public.
|
|
author (ForeignKey): A reference to the user who authored the post.
|
|
title (CharField): The title of the post. Must be unique and non-empty.
|
|
content (MarkdownField): The content of the post written in Markdown format.
|
|
file (FileField): An optional file attachment for the post.
|
|
slug (AutoSlugField): A unique, automatically generated slug based on the title.
|
|
tags (ManyToManyField): Tags associated with the post for categorization.
|
|
|
|
"""
|
|
|
|
is_publicly_visible = True
|
|
|
|
author = ForeignKey(to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts")
|
|
title = CharField(
|
|
unique=True, max_length=128, blank=False, null=False, help_text=_("post title"), verbose_name=_("title")
|
|
)
|
|
content: MarkdownField = MarkdownField(
|
|
"content",
|
|
extensions=[
|
|
TocExtension(toc_depth=3),
|
|
"pymdownx.arithmatex",
|
|
"pymdownx.b64",
|
|
"pymdownx.betterem",
|
|
"pymdownx.blocks.admonition",
|
|
"pymdownx.blocks.caption",
|
|
"pymdownx.blocks.definition",
|
|
"pymdownx.blocks.details",
|
|
"pymdownx.blocks.html",
|
|
"pymdownx.blocks.tab",
|
|
"pymdownx.caret",
|
|
"pymdownx.critic",
|
|
"pymdownx.emoji",
|
|
"pymdownx.escapeall",
|
|
"pymdownx.extra",
|
|
"pymdownx.fancylists",
|
|
"pymdownx.highlight",
|
|
"pymdownx.inlinehilite",
|
|
"pymdownx.keys",
|
|
"pymdownx.magiclink",
|
|
"pymdownx.mark",
|
|
"pymdownx.pathconverter",
|
|
"pymdownx.progressbar",
|
|
"pymdownx.saneheaders",
|
|
"pymdownx.smartsymbols",
|
|
"pymdownx.snippets",
|
|
"pymdownx.striphtml",
|
|
"pymdownx.superfences",
|
|
"pymdownx.tasklist",
|
|
"pymdownx.tilde",
|
|
],
|
|
blank=True,
|
|
null=True,
|
|
)
|
|
file = FileField(upload_to="posts/", blank=True, null=True)
|
|
slug = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
|
|
tags = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
|
|
meta_description = CharField(max_length=150, blank=True, null=True)
|
|
|
|
def __str__(self):
|
|
return f"{self.title} | {self.author.first_name} {self.author.last_name}"
|
|
|
|
class Meta:
|
|
verbose_name = _("post")
|
|
verbose_name_plural = _("posts")
|
|
|
|
def save(self, **kwargs):
|
|
if self.file:
|
|
raise ValueError(_("markdown files are not supported yet - use markdown content instead"))
|
|
if not any([self.file, self.content]) or all([self.file, self.content]):
|
|
raise ValueError(_("a markdown file or markdown content must be provided - mutually exclusive"))
|
|
super().save(**kwargs)
|
|
|
|
|
|
class PostTag(NiceModel):
|
|
"""
|
|
Represents a tag associated with a post.
|
|
|
|
The PostTag class is used to define and manage tags that can be assigned
|
|
to posts. These tags include an internal identifier and a user-friendly
|
|
display name. The class supports internationalization for both the internal
|
|
identifier and the display name.
|
|
|
|
Attributes:
|
|
is_publicly_visible (bool): Determines if the tag is visible publicly.
|
|
tag_name (CharField): An internal tag identifier for the post's tag. It is a required
|
|
field with a maximum length of 255 characters.
|
|
name (CharField): A user-friendly, unique display name for the post's tag
|
|
with a maximum length of 255 characters.
|
|
|
|
Meta:
|
|
verbose_name (str): Human-readable singular name of the PostTag model.
|
|
verbose_name_plural (str): Human-readable plural name of the PostTag model.
|
|
"""
|
|
|
|
is_publicly_visible = True
|
|
posts: "Post"
|
|
|
|
tag_name = CharField(
|
|
blank=False,
|
|
null=False,
|
|
max_length=255,
|
|
help_text=_("internal tag identifier for the post tag"),
|
|
verbose_name=_("tag name"),
|
|
)
|
|
name = CharField(
|
|
max_length=255,
|
|
help_text=_("user-friendly name for the post tag"),
|
|
verbose_name=_("tag display name"),
|
|
unique=True,
|
|
)
|
|
|
|
def __str__(self):
|
|
return self.tag_name
|
|
|
|
class Meta:
|
|
verbose_name = _("post tag")
|
|
verbose_name_plural = _("post tags")
|