Fixes: 1) Correct default values and type handling in util constructors; 2) Resolve missing or ambiguous `cast` operations for dynamic typing in tests and views; 3) Address potential issues with fallback/default handling in middleware. Extra: 1) Refactor test cases to ensure stricter adherence to typing hints and valid contracts; 2) Update docstrings to align with new type annotations; 3) Cleanup unused imports and add comments for improved maintainability.
159 lines
5.1 KiB
Python
159 lines
5.1 KiB
Python
from django.conf import settings
|
|
from django.db.models import (
|
|
CASCADE,
|
|
BooleanField,
|
|
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 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: 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)
|
|
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, **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")
|