diff --git a/config/settings.py b/config/settings.py index d688f2c..cf71219 100644 --- a/config/settings.py +++ b/config/settings.py @@ -237,3 +237,4 @@ CACHE_RECENT_PUBLISHED_POSTS: bool = False RECENT_PUBLISHED_POSTS_COUNT: int = 20 BLOG_TITLE = "stuartm.nz" +MARKDOWN_EXTENSIONS = ["fenced_code", "codehilite"] diff --git a/djpress/feeds.py b/djpress/feeds.py index a5b4036..407b0ce 100644 --- a/djpress/feeds.py +++ b/djpress/feeds.py @@ -20,14 +20,18 @@ class PostFeed(Feed): def items(self: "PostFeed") -> "models.QuerySet": """Return the most recent posts.""" - return Post.post_objects.get_recent_published_content() + return Post.post_objects.get_recent_published_posts() def item_title(self: "PostFeed", item: Post) -> str: """Return the title of the post.""" return item.title def item_description(self: "PostFeed", item: Post) -> str: - """Return the description of the post.""" + """Return the description of the post. + + This is taken from the truncated content of the post converted to HTML from + Markdown. + """ description = item.truncated_content_markdown if item.is_truncated: description += f'

Read more

' @@ -35,4 +39,4 @@ def item_description(self: "PostFeed", item: Post) -> str: def item_link(self: "PostFeed", item: Post) -> str: """Return the link to the post.""" - return reverse("djpress:content_detail", args=[item.slug]) + return reverse("djpress:post_detail", args=[item.slug]) diff --git a/djpress/migrations/0002_rename_content_type_post_post_type.py b/djpress/migrations/0002_rename_content_type_post_post_type.py new file mode 100644 index 0000000..040dd42 --- /dev/null +++ b/djpress/migrations/0002_rename_content_type_post_post_type.py @@ -0,0 +1,18 @@ +# Generated by Django 5.0.4 on 2024-05-03 11:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('djpress', '0001_initial'), + ] + + operations = [ + migrations.RenameField( + model_name='post', + old_name='content_type', + new_name='post_type', + ), + ] diff --git a/djpress/models/post.py b/djpress/models/post.py index d13d11a..a297a03 100644 --- a/djpress/models/post.py +++ b/djpress/models/post.py @@ -1,6 +1,5 @@ """Post model.""" -import logging from typing import ClassVar import markdown @@ -12,17 +11,15 @@ from config.settings import ( CACHE_RECENT_PUBLISHED_POSTS, + MARKDOWN_EXTENSIONS, RECENT_PUBLISHED_POSTS_COUNT, TRUNCATE_TAG, ) from djpress.models import Category -logger = logging.getLogger(__name__) +md = markdown.Markdown(extensions=MARKDOWN_EXTENSIONS, output_format="html") -markdown_extensions = ["fenced_code", "codehilite"] -md = markdown.Markdown(extensions=markdown_extensions, output_format="html") - -PUBLISHED_CONTENT_CACHE_KEY = "published_content" +PUBLISHED_POSTS_CACHE_KEY = "published_posts" class PostsManager(models.Manager): @@ -30,9 +27,9 @@ class PostsManager(models.Manager): def get_queryset(self: "PostsManager") -> models.QuerySet: """Return the queryset for published posts.""" - return super().get_queryset().filter(content_type="post").order_by("-date") + return super().get_queryset().filter(post_type="post").order_by("-date") - def _get_published_content(self: "PostsManager") -> models.QuerySet: + def _get_published_posts(self: "PostsManager") -> models.QuerySet: """Returns all published posts. For a post to be considered published, it must meet the following requirements: @@ -44,26 +41,25 @@ def _get_published_content(self: "PostsManager") -> models.QuerySet: date__lte=timezone.now(), ) - def get_recent_published_content(self: "PostsManager") -> models.QuerySet: + def get_recent_published_posts(self: "PostsManager") -> models.QuerySet: """Return recent published posts. If CACHE_RECENT_PUBLISHED_POSTS is set to True, we return the cached queryset. """ if CACHE_RECENT_PUBLISHED_POSTS: - return self._get_cached_recent_published_content() + return self._get_cached_recent_published_posts() - return self._get_published_content().prefetch_related("categories", "author")[ + return self._get_published_posts().prefetch_related("categories", "author")[ :RECENT_PUBLISHED_POSTS_COUNT ] - def _get_cached_recent_published_content(self: "PostsManager") -> models.QuerySet: + def _get_cached_recent_published_posts(self: "PostsManager") -> models.QuerySet: """Return the cached recent published posts queryset. If there are any future posts, we calculate the seconds until that post, then we set the timeout to that number of seconds. """ - queryset = cache.get(PUBLISHED_CONTENT_CACHE_KEY) - logger.debug(f"Getting posts from cache: {queryset=}") + queryset = cache.get(PUBLISHED_POSTS_CACHE_KEY) if queryset is None: queryset = ( @@ -78,25 +74,18 @@ def _get_cached_recent_published_content(self: "PostsManager") -> models.QuerySe if future_posts.exists(): future_post = future_posts[0] timeout = (future_post.date - timezone.now()).total_seconds() - logger.debug(f"Future post found, setting timeout to {timeout} seconds") else: - logger.debug("No future posts found, setting timeout to None") timeout = None queryset = queryset.filter(date__lte=timezone.now())[ :RECENT_PUBLISHED_POSTS_COUNT ] - logger.debug(f"Setting posts in cache: {queryset=}") - logger.debug(f"With a timeout of: {timeout=}") cache.set( - PUBLISHED_CONTENT_CACHE_KEY, + PUBLISHED_POSTS_CACHE_KEY, queryset, timeout=timeout, ) - logger.debug( - f"Posts set in cache: {cache.get(PUBLISHED_CONTENT_CACHE_KEY)=}", - ) return queryset def get_published_post_by_slug( @@ -107,33 +96,31 @@ def get_published_post_by_slug( Must have a date less than or equal to the current date/time based on its slug. """ - logger.debug(f"Getting post by slug: {slug=}") - # First, try to get the post from the cache - posts = self.get_recent_published_content() + posts = self.get_recent_published_posts() post = next((post for post in posts if post.slug == slug), None) # If the post is not found in the cache, fetch it from the database if not post: try: - post = self._get_published_content().get(slug=slug) + post = self._get_published_posts().get(slug=slug) except Post.DoesNotExist as exc: msg = "Post not found" raise ValueError(msg) from exc return post - def get_published_content_by_category( + def get_published_posts_by_category( self: "PostsManager", category: Category, ) -> models.QuerySet: - """Return all published posts. + """Return all published posts for a given category. Must have a date less than or equal to the current date/time for a specific category, ordered by date in descending order. """ return ( - self._get_published_content() + self._get_published_posts() .filter(categories=category) .prefetch_related("categories", "author") ) @@ -152,7 +139,7 @@ class Post(models.Model): date = models.DateTimeField(default=timezone.now) modified_date = models.DateTimeField(auto_now=True) status = models.CharField(max_length=10, choices=STATUS_CHOICES, default="draft") - content_type = models.CharField( + post_type = models.CharField( max_length=10, choices=CONTENT_TYPE_CHOICES, default="post", @@ -164,13 +151,13 @@ class Post(models.Model): post_objects: "PostsManager" = PostsManager() class Meta: - """Meta options for the content model.""" + """Meta options for the Post model.""" verbose_name = "post" verbose_name_plural = "posts" def __str__(self: "Post") -> str: - """Return the string representation of the content.""" + """Return the string representation of the post.""" return self.title def save(self: "Post", *args, **kwargs) -> None: # noqa: ANN002, ANN003 @@ -185,7 +172,6 @@ def save(self: "Post", *args, **kwargs) -> None: # noqa: ANN002, ANN003 def render_markdown(self: "Post", markdown_text: str) -> str: """Return the markdown text as HTML.""" html = md.convert(markdown_text) - logger.debug(f"Converted markdown to HTML: {html=}") md.reset() return html @@ -209,3 +195,11 @@ def truncated_content_markdown(self: "Post") -> str: def is_truncated(self: "Post") -> bool: """Return whether the content is truncated.""" return TRUNCATE_TAG in self.content + + @property + def author_display_name(self: "Post") -> str: + """Return the author's display name. + + If the author has a first name, return that. Otherwise, return the username. + """ + return self.author.first_name or self.author.username diff --git a/djpress/signals.py b/djpress/signals.py index fd1513d..d51c336 100644 --- a/djpress/signals.py +++ b/djpress/signals.py @@ -9,7 +9,7 @@ Category, ) from djpress.models.post import ( - PUBLISHED_CONTENT_CACHE_KEY, + PUBLISHED_POSTS_CACHE_KEY, Post, ) @@ -25,4 +25,4 @@ def invalidate_category_cache(**kwargs) -> None: # noqa: ARG001, ANN003 @receiver(post_delete, sender=Post) def invalidate_published_content_cache(**kwargs) -> None: # noqa: ARG001, ANN003 """Invalidate the published posts cache.""" - cache.delete(PUBLISHED_CONTENT_CACHE_KEY) + cache.delete(PUBLISHED_POSTS_CACHE_KEY) diff --git a/djpress/templates/djpress/index.html b/djpress/templates/djpress/index.html index 39086b7..1886a63 100644 --- a/djpress/templates/djpress/index.html +++ b/djpress/templates/djpress/index.html @@ -22,7 +22,7 @@

{% get_blog_title %}

{{ post.title }}

-

By

+

By

@@ -52,15 +52,15 @@

{{ category.name }}

-

{{ post.title }}

-

By

+

{{ post.title }}

+

By

{{ post.truncated_content_markdown|safe }} {% if post.is_truncated %} -

Read more

+

Read more

{% endif %}