The blog application for django CMS providing multilingual blog functionality with advanced content management features
—
Template tags for extracting media content from posts, utility functions, and helper classes for template integration and content management.
Template tags for working with media attachments in blog posts.
@register.simple_tag(name="media_plugins", takes_context=True)
def media_plugins(context: Dict[str, Any], post: Post) -> List[CMSPlugin]:
"""
Extract MediaAttachmentPluginMixin plugins from post media placeholder.
Parameters:
- context: Template context dictionary
- post: Post instance to extract media from
Returns:
List of MediaAttachmentPluginMixin plugins from the media placeholder
Usage in templates:
{% media_plugins post as media_plugins %}
{% for plugin in media_plugins %}{% render_plugin plugin %}{% endfor %}
"""
@register.simple_tag(name="media_images", takes_context=True)
def media_images(context: Dict[str, Any], post: Post, main: bool = True) -> List[str]:
"""
Extract images from MediaAttachmentPluginMixin plugins in post media placeholder.
Parameters:
- context: Template context dictionary
- post: Post instance to extract images from
- main: If True, get main images; if False, get thumbnail images
Returns:
List of image URLs from media plugins
Features:
- Supports main images and thumbnails
- Handles djangocms-video poster field fallback
- Graceful error handling for missing methods
Usage in templates:
{% media_images post False as thumbs %}
{% for thumb in thumbs %}<img src="{{ thumb }}"/>{% endfor %}
{% media_images post as main_images %}
{% for image in main_images %}<img src="{{ image }}"/>{% endfor %}
"""Core utility functions for slug generation and text processing.
def slugify(base: str) -> str:
"""
Generate URL-friendly slugs with unicode support.
Parameters:
- base: String to convert to slug
Returns:
URL-friendly slug string
Features:
- Respects BLOG_UNICODE_SLUGS setting
- Uses Django's slugify with unicode support
- Consistent slug generation across the application
"""Custom manager classes for advanced querying and filtering.
class TaggedFilterItem:
"""
Manager mixin for tag filtering functionality.
Features:
- Tag-based content filtering
- Related content discovery
- Cross-model tag relationships
"""
def tagged(self, other_model: Optional[models.Model] = None, queryset: Optional[QuerySet] = None) -> QuerySet:
"""
Return queryset of items tagged with same tags as other model/queryset.
Parameters:
- other_model: Model instance to match tags with
- queryset: QuerySet to match tags with
Returns:
QuerySet filtered by matching tags
"""
def _taglist(self, other_model: Optional[models.Model] = None, queryset: Optional[QuerySet] = None) -> List[int]:
"""
Return list of tag IDs common to current model and provided model/queryset.
Parameters:
- other_model: Model instance to find common tags with
- queryset: QuerySet to find common tags with
Returns:
List of tag IDs that are common between models
"""
def tag_list(self, other_model: Optional[models.Model] = None, queryset: Optional[QuerySet] = None) -> QuerySet:
"""
Return queryset of tags common to current model and provided model/queryset.
Parameters:
- other_model: Model instance to find common tags with
- queryset: QuerySet to find common tags with
Returns:
QuerySet of Tag objects that are common
"""
class GenericDateTaggedManager(TaggedFilterItem, AppHookConfigTranslatableManager):
"""
Manager combining date filtering, tag filtering, and app config support.
Features:
- App config filtering
- Multilingual content support
- Tag-based filtering
- Date-based filtering
- Publication status filtering
"""
def published(self) -> QuerySet:
"""Return published posts queryset."""
def archived(self) -> QuerySet:
"""Return archived posts queryset."""
def available(self) -> QuerySet:
"""Return posts available for current site."""
def by_author(self, author: AbstractUser) -> QuerySet:
"""Return posts by specific author."""
def by_category(self, category: BlogCategory) -> QuerySet:
"""Return posts in specific category."""
def by_tag(self, tag: str) -> QuerySet:
"""Return posts with specific tag."""
def featured(self) -> QuerySet:
"""Return featured posts."""
def recent(self, count: int = 5) -> QuerySet:
"""Return recent posts."""Context processors for adding blog-related data to template contexts.
# Context data automatically available in templates when using blog views:
# - post: Current post object (in detail views)
# - post_list: List of posts (in list views)
# - categories: Available categories
# - tags: Available tags
# - config: Current blog configuration
# - meta: Meta information for SEO
# - view: Current view instance# Using template tags in templates
# Load the template tags
{% load cms_tags djangocms_blog %}
# Extract and display media plugins
{% media_plugins post as media_plugins %}
{% if media_plugins %}
<div class="post-media">
{% for plugin in media_plugins %}
{% render_plugin plugin %}
{% endfor %}
</div>
{% endif %}
# Display media images
{% media_images post as main_images %}
{% if main_images %}
<div class="post-images">
{% for image in main_images %}
<img src="{{ image }}" alt="{{ post.title }}" class="post-image">
{% endfor %}
</div>
{% endif %}
# Display thumbnail images
{% media_images post False as thumbs %}
{% if thumbs %}
<div class="post-thumbnails">
{% for thumb in thumbs %}
<img src="{{ thumb }}" alt="{{ post.title }}" class="post-thumb">
{% endfor %}
</div>
{% endif %}
# Custom template tag usage
from django import template
from djangocms_blog.models import Post
from djangocms_blog.templatetags.djangocms_blog import media_images
register = template.Library()
@register.simple_tag
def post_gallery(post, image_type='main'):
"""Custom tag for post image gallery."""
if image_type == 'main':
images = media_images({'request': None}, post, main=True)
else:
images = media_images({'request': None}, post, main=False)
return {
'images': images,
'post': post,
'image_type': image_type
}
# Using utility functions
from djangocms_blog.fields import slugify
# Generate slugs
title = "My Awesome Blog Post with Ñoño Characters"
slug = slugify(title) # Returns "my-awesome-blog-post-with-ñoño-characters"
# Custom slug generation
def generate_unique_slug(title, model_class, instance=None):
"""Generate unique slug for model instance."""
base_slug = slugify(title)
slug = base_slug
counter = 1
queryset = model_class.objects.all()
if instance and instance.pk:
queryset = queryset.exclude(pk=instance.pk)
while queryset.filter(slug=slug).exists():
slug = f"{base_slug}-{counter}"
counter += 1
return slug
# Using manager utilities
from djangocms_blog.models import Post
# Find posts with similar tags
main_post = Post.objects.get(pk=1)
related_posts = Post.objects.tagged(main_post)[:5]
# Find posts tagged with same tags as a set of posts
featured_posts = Post.objects.featured()
similar_posts = Post.objects.tagged(queryset=featured_posts)
# Complex querying with manager
from djangocms_blog.managers import GenericDateTaggedManager
class CustomPostManager(GenericDateTaggedManager):
"""Custom manager with additional methods."""
def by_year(self, year):
"""Get posts by year."""
return self.published().filter(date_published__year=year)
def popular(self, limit=10):
"""Get popular posts (example implementation)."""
return self.published().order_by('-views')[:limit]
def with_images(self):
"""Get posts that have main images."""
return self.published().exclude(main_image__isnull=True)
# Template context usage
# In templates, access manager methods:
# {% for post in view.get_queryset.featured %}
# {% for post in view.get_queryset.by_author:request.user %}
# {% for post in view.get_queryset.recent:10 %}
# Custom template filters
from django import template
from django.utils.safestring import mark_safe
from djangocms_blog.fields import slugify
register = template.Library()
@register.filter
def blog_slugify(value):
"""Template filter for slug generation."""
return slugify(str(value))
@register.filter
def post_excerpt(post, length=150):
"""Generate post excerpt."""
if post.abstract:
text = post.abstract
elif post.post_text:
text = post.post_text
else:
return ""
# Strip HTML and truncate
from django.utils.html import strip_tags
from django.utils.text import Truncator
plain_text = strip_tags(text)
truncated = Truncator(plain_text).chars(length, truncate='...')
return mark_safe(truncated)
# Usage in templates:
# {{ post.title|blog_slugify }}
# {{ post|post_excerpt:200 }}
# Custom inclusion tags
@register.inclusion_tag('blog/tags/related_posts.html', takes_context=True)
def related_posts(context, post, count=5):
"""Inclusion tag for related posts."""
related = Post.objects.published().tagged(post).exclude(pk=post.pk)[:count]
return {
'related_posts': related,
'current_post': post,
'request': context.get('request')
}
# Usage: {% related_posts post 3 %}Install with Tessl CLI
npx tessl i tessl/pypi-djangocms-blog