The blog application for django CMS providing multilingual blog functionality with advanced content management features
—
Per-apphook configuration system enabling multiple blog instances with different settings, plus global settings management and customization options.
Translatable configuration model for individual blog instances with per-apphook settings.
class BlogConfig(TranslatableModel, AppHookConfig):
"""
Translatable configuration model for blog app instances.
Translated fields:
- app_title: CharField(max_length=234) - Application title
- object_name: CharField(max_length=234) - Object name for wizards
Features:
- Per-apphook configuration
- Multilingual configuration options
- Template and permalink customization
- SEO and social media settings
"""
translations: TranslatedFields = TranslatedFields(
app_title=models.CharField(_("application title"), max_length=234),
object_name=models.CharField(
_("object name"),
max_length=234,
default=get_setting("DEFAULT_OBJECT_NAME")
),
)
def get_app_title(self) -> str:
"""Return the application title."""
@property
def schemaorg_type(self) -> str:
"""Return schema.org type for structured data."""Comprehensive form for blog configuration with all available settings.
class BlogConfigForm(AppDataForm):
"""
Settings that can be changed per-apphook.
Configuration options include:
- Template settings
- Permalink configuration
- SEO and meta tag settings
- Social media integration
- RSS feed settings
- Comment settings
- Menu and navigation options
"""
# Basic settings
app_title: str = get_setting("AUTO_APP_TITLE")
object_name: str = get_setting("DEFAULT_OBJECT_NAME")
# Template settings
template_prefix: str = get_setting("TEMPLATE_PREFIX")
menu_structure: str = get_setting("MENU_TYPE")
menu_empty_categories: bool = get_setting("MENU_EMPTY_CATEGORIES")
# Permalink settings
permalink_type: str = get_setting("PERMALINK_TYPE")
url_patterns: str = get_setting("URL_PATTERNS")
# SEO settings
meta_title: str = get_setting("META_TITLE")
meta_description: str = get_setting("META_DESCRIPTION")
meta_keywords: str = get_setting("META_KEYWORDS")
# Social media settings
facebook_type: str = get_setting("FB_TYPE")
facebook_app_id: str = get_setting("FB_APP_ID")
twitter_type: str = get_setting("TWITTER_TYPE")
twitter_site: str = get_setting("TWITTER_SITE")
twitter_author: str = get_setting("TWITTER_AUTHOR")
gplus_type: str = get_setting("GPLUS_TYPE")
# RSS and feed settings
feed_latest_items: int = get_setting("FEED_LATEST_ITEMS")
feed_enable: bool = get_setting("FEED_ENABLE")
# Sitemap settings
sitemap_priority_default: float = get_setting("SITEMAP_PRIORITY_DEFAULT")
sitemap_changefreq_default: str = get_setting("SITEMAP_CHANGEFREQ_DEFAULT")
# Display settings
pagination: int = get_setting("PAGINATION")
latest_posts: int = get_setting("LATEST_POSTS")
multisite: bool = get_setting("MULTISITE")
# Comment settings
enable_comments: bool = get_setting("ENABLE_COMMENTS")
use_placeholder: bool = get_setting("USE_PLACEHOLDER")Global settings system with customizable defaults and runtime configuration.
def get_setting(name: str) -> Any:
"""
Get blog setting value with fallback to defaults.
Parameters:
- name: Setting name to retrieve
Returns:
Setting value from Django settings or package default
Example settings:
- BLOG_PAGINATION: Number of posts per page
- BLOG_LATEST_POSTS: Number of latest posts to show
- BLOG_ENABLE_COMMENTS: Enable comment system
- BLOG_USE_PLACEHOLDER: Use placeholder fields
- BLOG_MULTISITE: Enable multisite support
- BLOG_MENU_TYPE: Menu structure type
- BLOG_PERMALINK_TYPE: Permalink pattern type
- BLOG_TEMPLATE_PREFIX: Template prefix for customization
"""
# Setting constants and choices
MENU_TYPE_COMPLETE: str = "complete"
MENU_TYPE_CATEGORIES: str = "categories"
MENU_TYPE_POSTS: str = "posts"
MENU_TYPE_NONE: str = "none"
PERMALINK_TYPE_FULL_DATE: str = "full_date"
PERMALINK_TYPE_SHORT_DATE: str = "short_date"
PERMALINK_TYPE_CATEGORY: str = "category"
PERMALINK_TYPE_SLUG: str = "slug"
PERMALINKS: List[Tuple[str, str]] = [
(PERMALINK_TYPE_FULL_DATE, _("Full date")),
(PERMALINK_TYPE_SHORT_DATE, _("Year / Month")),
(PERMALINK_TYPE_CATEGORY, _("Category")),
(PERMALINK_TYPE_SLUG, _("Just slug")),
]
PERMALINKS_URLS: Dict[str, str] = {
PERMALINK_TYPE_FULL_DATE: "<int:year>/<int:month>/<int:day>/<str:slug>/",
PERMALINK_TYPE_SHORT_DATE: "<int:year>/<int:month>/<str:slug>/",
PERMALINK_TYPE_CATEGORY: "<str:category>/<str:slug>/",
PERMALINK_TYPE_SLUG: "<str:slug>/",
}Complete list of configurable settings with their default values.
# Blog behavior settings
BLOG_DEFAULT_PUBLISHED: bool = False
BLOG_UNICODE_SLUGS: bool = True
BLOG_MULTISITE: bool = True
BLOG_USE_PLACEHOLDER: bool = True
BLOG_USE_ABSTRACT: bool = True
BLOG_USE_LIVEBLOG: bool = False
# Display settings
BLOG_PAGINATION: int = 10
BLOG_LATEST_POSTS: int = 5
BLOG_MENU_TYPE: str = MENU_TYPE_COMPLETE
BLOG_MENU_EMPTY_CATEGORIES: bool = False
# Template settings
BLOG_TEMPLATE_PREFIX: str = 'djangocms_blog'
BLOG_PLUGIN_TEMPLATE_FOLDERS: List[str] = ['plugins']
# URL and permalink settings
BLOG_PERMALINK_TYPE: str = PERMALINK_TYPE_SLUG
BLOG_URL_PATTERNS: str = 'djangocms_blog.urls'
# SEO and meta settings
BLOG_META_TITLE: str = ''
BLOG_META_DESCRIPTION: str = ''
BLOG_META_KEYWORDS: str = ''
BLOG_AUTO_APP_TITLE: bool = True
BLOG_DEFAULT_OBJECT_NAME: str = _('Article')
# Social media settings
BLOG_FB_TYPE: str = 'article'
BLOG_FB_APP_ID: str = ''
BLOG_TWITTER_TYPE: str = 'summary'
BLOG_TWITTER_SITE: str = ''
BLOG_TWITTER_AUTHOR: str = ''
BLOG_GPLUS_TYPE: str = 'Article'
# Feed settings
BLOG_FEED_ENABLE: bool = True
BLOG_FEED_LATEST_ITEMS: int = 10
# Sitemap settings
BLOG_SITEMAP_PRIORITY_DEFAULT: float = 0.5
BLOG_SITEMAP_CHANGEFREQ_DEFAULT: str = 'monthly'
# Comment settings
BLOG_ENABLE_COMMENTS: bool = True
BLOG_CURRENT_POST_IDENTIFIER: str = 'CURRENT_POST'
BLOG_CURRENT_NAMESPACE: str = 'CURRENT_NAMESPACE'# Django settings.py configuration
# Override default blog settings
BLOG_PAGINATION = 20
BLOG_LATEST_POSTS = 10
BLOG_MENU_TYPE = 'categories'
BLOG_PERMALINK_TYPE = 'full_date'
BLOG_USE_PLACEHOLDER = True
BLOG_MULTISITE = True
BLOG_ENABLE_COMMENTS = False
# SEO configuration
BLOG_META_TITLE = 'My Blog - Latest News and Articles'
BLOG_META_DESCRIPTION = 'Stay updated with our latest blog posts'
BLOG_META_KEYWORDS = 'blog, news, articles, updates'
# Social media configuration
BLOG_FB_APP_ID = '1234567890123456'
BLOG_TWITTER_SITE = '@myblog'
BLOG_TWITTER_AUTHOR = '@author'
# Template customization
BLOG_TEMPLATE_PREFIX = 'custom_blog'
BLOG_PLUGIN_TEMPLATE_FOLDERS = ['custom_plugins', 'blog_plugins']
# Creating blog configurations programmatically
from djangocms_blog.cms_appconfig import BlogConfig
# Create a new blog configuration
config = BlogConfig.objects.create(
namespace='news-blog',
app_title='News Blog',
object_name='News Article'
)
# Set translated fields
config.set_current_language('en')
config.app_title = 'Company News'
config.object_name = 'News Article'
config.save()
config.set_current_language('es')
config.app_title = 'Noticias de la Empresa'
config.object_name = 'Artículo de Noticias'
config.save()
# Configure per-apphook settings
config.app_data.config.permalink_type = 'full_date'
config.app_data.config.pagination = 15
config.app_data.config.enable_comments = False
config.app_data.config.meta_title = 'Company News - Latest Updates'
config.save()
# Access configuration in views/templates
from aldryn_apphooks_config.utils import get_app_instance
def my_view(request):
namespace, config = get_app_instance(request)
# Access configuration settings
pagination = config.app_data.config.pagination or get_setting('PAGINATION')
enable_comments = config.app_data.config.enable_comments
meta_title = config.app_data.config.meta_title
# Use in queryset
posts = Post.objects.published().filter(app_config=config)
return render(request, 'blog/posts.html', {
'posts': posts,
'config': config,
'pagination': pagination
})
# Template usage
# {% load cms_tags %}
# {% page_attribute "app_config" as config %}
#
# <h1>{{ config.app_title }}</h1>
# <meta name="description" content="{{ config.app_data.config.meta_description }}">
#
# {% if config.app_data.config.enable_comments %}
# <!-- Comment system -->
# {% endif %}
# Custom configuration validation
from djangocms_blog.cms_appconfig import BlogConfigForm
class CustomBlogConfigForm(BlogConfigForm):
"""Custom configuration form with additional validation."""
custom_setting = forms.CharField(
label='Custom Setting',
required=False,
help_text='Enter a custom value for this blog instance'
)
def clean_pagination(self):
"""Validate pagination setting."""
pagination = self.cleaned_data.get('pagination')
if pagination and pagination > 50:
raise forms.ValidationError('Pagination cannot exceed 50 posts per page.')
return pagination
# Using settings in custom code
from djangocms_blog.settings import get_setting
# Get setting with fallback
pagination = get_setting('PAGINATION') # Returns 10 by default
custom_setting = get_setting('CUSTOM_SETTING') # Returns None if not defined
# Override settings per request/context
class CustomPostListView(PostListView):
def get_paginate_by(self, queryset):
"""Custom pagination based on configuration."""
if hasattr(self, 'config') and self.config:
return self.config.app_data.config.pagination or get_setting('PAGINATION')
return get_setting('PAGINATION')Install with Tessl CLI
npx tessl i tessl/pypi-djangocms-blog