schon/engine/blog/models.py
2026-01-26 03:23:41 +03:00

125 lines
3.9 KiB
Python

from django.conf import settings
from django.db.models import (
CASCADE,
BooleanField,
CharField,
FileField,
ForeignKey,
ManyToManyField,
TextField,
)
from django.utils.translation import gettext_lazy as _
from django_extensions.db.fields import AutoSlugField
from engine.core.abstract import NiceModel
class Post(NiceModel):
__doc__ = _( # pyright: ignore[reportUnknownVariableType]
"Represents a blog post model. "
"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."
)
is_publicly_visible = True
author = ForeignKey(
to=settings.AUTH_USER_MODEL,
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 = TextField(
verbose_name=_("content"),
help_text=_("post content"),
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)
is_static_page = BooleanField(
default=False,
verbose_name=_("is static page"),
help_text=_(
"is this a post for a page with static URL (e.g. `/help/delivery`)?"
),
)
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, *args, **kwargs):
if self.file:
raise ValueError(
_("file uploads are not supported yet - use content instead")
)
if not any([self.file, self.content]) or all([self.file, self.content]):
raise ValueError(
_("a file or content must be provided - mutually exclusive")
)
super().save(*args, **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")