schon/blog/models.py
Egor fureunoir Gorbunov 856f2ff516 Features: 1) Add app_name attribute in multiple urls.py files across apps to support namespacing;
Fixes: 1) Simplify Prometheus and GraphQL path definitions in `evibes/api_urls.py`;

Extra: 1) Add line breaks across multiple files for improved code readability.
2025-06-29 20:03:33 +03:00

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):
"""
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 = ForeignKey(
to="vibes_auth.User", on_delete=CASCADE, blank=False, null=False, related_name="posts"
)
title: CharField = 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 = FileField(upload_to="posts/", blank=True, null=True)
slug: AutoSlugField = AutoSlugField(populate_from="title", allow_unicode=True, unique=True, editable=False)
tags: ManyToManyField = ManyToManyField(to="blog.PostTag", blank=True, related_name="posts")
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 tag. It is a required
field with a maximum length of 255 characters.
name (CharField): A user-friendly, unique display name for the post 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
tag_name: CharField = CharField(
blank=False,
null=False,
max_length=255,
help_text=_("internal tag identifier for the post tag"),
verbose_name=_("tag name"),
)
name: CharField = 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")