Add support for apphook config

This commit is contained in:
Iacopo Spalletti 2015-09-20 01:11:14 +02:00
commit f6e8e27687
23 changed files with 1308 additions and 428 deletions

View file

@ -3,6 +3,7 @@ from __future__ import absolute_import, print_function, unicode_literals
from copy import deepcopy
from aldryn_apphooks_config.admin import BaseAppHookConfig, ModelAppHookConfig
from cms.admin.placeholderadmin import FrontendEditableAdminMixin, PlaceholderAdminMixin
from django import forms
from django.conf import settings
@ -10,6 +11,8 @@ from django.contrib import admin
from django.contrib.auth import get_user_model
from parler.admin import TranslatableAdmin
from .cms_appconfig import BlogConfig
from .forms import PostAdminForm
from .models import BlogCategory, Post
from .settings import get_setting
@ -20,19 +23,22 @@ except ImportError:
pass
class BlogCategoryAdmin(EnhancedModelAdminMixin, TranslatableAdmin):
class BlogCategoryAdmin(EnhancedModelAdminMixin, ModelAppHookConfig, TranslatableAdmin):
def get_prepopulated_fields(self, request, obj=None):
app_config_default = self._app_config_select(request, obj)
if app_config_default is None and request.method == 'GET':
return {}
return {'slug': ('name',)}
class Media:
css = {
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
'djangocms_blog_admin.css'),)
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL, 'djangocms_blog_admin.css'),)
}
class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
PlaceholderAdminMixin, TranslatableAdmin):
class PostAdmin(PlaceholderAdminMixin, FrontendEditableAdminMixin,
ModelAppHookConfig, TranslatableAdmin):
form = PostAdminForm
list_display = ['title', 'author', 'date_published', 'date_published_end']
date_hierarchy = 'date_published'
raw_id_fields = ['author']
@ -40,7 +46,7 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
enhance_exclude = ('main_image', 'tags')
_fieldsets = [
(None, {
'fields': [('title', 'categories', 'publish')]
'fields': [('title', 'categories', 'publish', 'app_config')]
}),
('Info', {
'fields': (['slug', 'tags'],
@ -57,6 +63,10 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
}),
]
app_config_values = {
'default_published': 'publish'
}
def formfield_for_dbfield(self, db_field, **kwargs):
field = super(PostAdmin, self).formfield_for_dbfield(db_field, **kwargs)
if db_field.name == 'meta_description':
@ -68,11 +78,25 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
return field
def get_fieldsets(self, request, obj=None):
app_config_default = self._app_config_select(request, obj)
if app_config_default is None and request.method == 'GET':
return super(PostAdmin, self).get_fieldsets(request, obj)
if not obj:
config = app_config_default
else:
config = obj.app_config
fsets = deepcopy(self._fieldsets)
if get_setting('USE_ABSTRACT'):
fsets[0][1]['fields'].append('abstract')
if not get_setting('USE_PLACEHOLDER'):
fsets[0][1]['fields'].append('post_text')
if config:
if config.use_abstract:
fsets[0][1]['fields'].append('abstract')
if not config.use_placeholder:
fsets[0][1]['fields'].append('post_text')
else:
if get_setting('USE_ABSTRACT'):
fsets[0][1]['fields'].append('abstract')
if not get_setting('USE_PLACEHOLDER'):
fsets[0][1]['fields'].append('post_text')
if get_setting('MULTISITE'):
fsets[1][1]['fields'][0].append('sites')
if request.user.is_superuser:
@ -83,7 +107,7 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
return {'slug': ('title',)}
def save_model(self, request, obj, form, change):
if not obj.author_id and get_setting('AUTHOR_DEFAULT'):
if not obj.author_id and obj.app_config.set_author:
if get_setting('AUTHOR_DEFAULT') is True:
user = request.user
else:
@ -93,10 +117,18 @@ class PostAdmin(EnhancedModelAdminMixin, FrontendEditableAdminMixin,
class Media:
css = {
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
'djangocms_blog_admin.css'),)
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL, 'djangocms_blog_admin.css'),)
}
class BlogConfigAdmin(BaseAppHookConfig, TranslatableAdmin):
def get_config_fields(self):
return (
'app_title', 'paginate_by', 'set_author', 'config.default_published',
'config.use_placeholder'
)
admin.site.register(BlogCategory, BlogCategoryAdmin)
admin.site.register(Post, PostAdmin)
admin.site.register(BlogConfig, BlogConfigAdmin)

View file

@ -1,17 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
from cms.app_base import CMSApp
from aldryn_apphooks_config.app_base import CMSConfigApp
from cms.apphook_pool import apphook_pool
from django.utils.translation import ugettext_lazy as _
from .cms_appconfig import BlogConfig
from .menu import BlogCategoryMenu
class BlogApp(CMSApp):
class BlogApp(CMSConfigApp):
name = _('Blog')
urls = ['djangocms_blog.urls']
app_name = 'djangocms_blog'
app_config = BlogConfig
menus = [BlogCategoryMenu]
apphook_pool.register(BlogApp)

View file

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django import forms
from django.db import models
from django.utils.translation import ugettext_lazy as _
from aldryn_apphooks_config.utils import setup_config
from aldryn_apphooks_config.models import AppHookConfig
from app_data import AppDataForm
from parler.models import TranslatableModel
from parler.models import TranslatedFields
from .settings import get_setting
class BlogConfig(TranslatableModel, AppHookConfig):
"""
Adds some translatable, per-app-instance fields.
"""
translations = TranslatedFields(
app_title=models.CharField(_('application title'), max_length=234),
)
def get_app_title(self):
return getattr(self, 'app_title', _('untitled'))
class BlogConfigForm(AppDataForm):
default_published = forms.BooleanField(label=_('Post published by default'), required=False,
initial=get_setting('DEFAULT_PUBLISHED'))
use_placeholder = forms.BooleanField(label=_('Use placeholder and plugins for article body'),
required=False,
initial=get_setting('USE_PLACEHOLDER'))
use_abstract = forms.BooleanField(label=_('Use abstract field'),
required=False,
initial=get_setting('USE_ABSTRACT'))
set_author = forms.BooleanField(label=_('Set author'),
required=False,
help_text=_('Set author by default'),
initial=get_setting('AUTHOR_DEFAULT'))
paginate_by = forms.IntegerField(label=_('Paginate size'),
required=False,
initial=get_setting('PAGINATION'),
help_text=_('When paginating list views, '
'how many articles per page?'))
setup_config(BlogConfigForm, BlogConfig)

View file

@ -7,7 +7,7 @@ from cms.plugin_pool import plugin_pool
from django.utils.translation import ugettext_lazy as _
from .forms import LatestEntriesForm
from .models import AuthorEntriesPlugin, BlogCategory, LatestPostsPlugin, Post
from .models import AuthorEntriesPlugin, BlogCategory, LatestPostsPlugin, Post, GenericBlogPlugin
from .settings import get_setting
@ -70,36 +70,47 @@ class BlogAuthorPostsPlugin(BlogPlugin):
class BlogTagsPlugin(BlogPlugin):
module = _('Blog')
name = _('Tags')
model = CMSPlugin
model = GenericBlogPlugin
render_template = 'djangocms_blog/plugins/tags.html'
def render(self, context, instance, placeholder):
context = super(BlogTagsPlugin, self).render(context, instance, placeholder)
context['tags'] = Post.objects.tag_cloud(queryset=Post.objects.published())
qs = Post._default_manager
qs_post = qs
if instance.app_config:
qs_post = qs_post.namespace(instance.app_config.namespace)
context['tags'] = qs.tag_cloud(queryset=qs_post.published())
return context
class BlogCategoryPlugin(BlogPlugin):
module = _('Blog')
name = _('Categories')
model = CMSPlugin
model = GenericBlogPlugin
render_template = 'djangocms_blog/plugins/categories.html'
def render(self, context, instance, placeholder):
context = super(BlogCategoryPlugin, self).render(context, instance, placeholder)
context['categories'] = BlogCategory.objects.all()
qs = BlogCategory._default_manager
if instance.app_config:
qs = qs.namespace(instance.app_config.namespace)
context['categories'] = qs
return context
class BlogArchivePlugin(BlogPlugin):
module = _('Blog')
name = _('Archive')
model = CMSPlugin
model = GenericBlogPlugin
render_template = 'djangocms_blog/plugins/archive.html'
def render(self, context, instance, placeholder):
context = super(BlogArchivePlugin, self).render(context, instance, placeholder)
context['dates'] = Post.objects.get_months(queryset=Post.objects.published())
qs = Post._default_manager
qs_post = qs
if instance.app_config:
qs_post = qs.namespace(instance.app_config.namespace)
context['dates'] = qs.get_months(queryset=qs_post.published())
return context

View file

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
from aldryn_apphooks_config.utils import get_app_instance
from django.contrib.sites.models import Site
from django.contrib.syndication.views import Feed
@ -12,14 +13,18 @@ from .settings import get_setting
class LatestEntriesFeed(Feed):
def __call__(self, request, *args, **kwargs):
self.namespace, self.config = get_app_instance(request)
return super(LatestEntriesFeed, self).__call__(request, *args, **kwargs)
def link(self):
return reverse('djangocms_blog:posts-latest')
return reverse('%s:posts-latest' % self.namespace, current_app=self.namespace)
def title(self):
return _('Blog articles on %(site_name)s') % {'site_name': Site.objects.get_current().name}
def items(self, obj=None):
return Post.objects.published().order_by('-date_published')[:10]
return Post.objects.namespace(self.namespace).published().order_by('-date_published')[:10]
def item_title(self, item):
return item.safe_translation_getter('title')

View file

@ -3,8 +3,11 @@ from __future__ import absolute_import, print_function, unicode_literals
from django import forms
from django.conf import settings
from parler.forms import TranslatableModelForm
from taggit_autosuggest.widgets import TagAutoSuggest
from .models import Post, BlogCategory
class LatestEntriesForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
@ -16,3 +19,28 @@ class LatestEntriesForm(forms.ModelForm):
'all': ('%sdjangocms_blog/css/%s' % (settings.STATIC_URL,
'djangocms_blog_admin.css'),)
}
class PostAdminForm(TranslatableModelForm):
class Meta:
model = Post
fields = '__all__'
def __init__(self, *args, **kwargs):
super(PostAdminForm, self).__init__(*args, **kwargs)
qs = BlogCategory.objects
if getattr(self.instance, 'app_config_id', None):
qs = qs.namespace(self.instance.app_config.namespace)
elif 'initial' in kwargs and 'app_config' in kwargs['initial']:
qs = qs.namespace(kwargs['initial']['app_config'])
if 'categories' in self.fields:
self.fields['categories'].queryset = qs
if 'app_config' in self.fields:
# Don't allow app_configs to be added here. The correct way to add an
# apphook-config is to create an apphook on a cms Page.
self.fields['app_config'].widget.can_add_related = False

View file

@ -2,10 +2,13 @@
from __future__ import absolute_import, print_function, unicode_literals
import django
from aldryn_apphooks_config.managers.parler import (
AppHookConfigTranslatableManager, AppHookConfigTranslatableQueryset
)
from django.contrib.sites.models import Site
from django.db import models
from django.utils.timezone import now
from parler.managers import TranslatableQuerySet, TranslationManager
try:
from collections import Counter
@ -76,7 +79,7 @@ class TaggedFilterItem(object):
return sorted(tags, key=lambda x: -x.count)
class GenericDateQuerySet(TranslatableQuerySet):
class GenericDateQuerySet(AppHookConfigTranslatableQueryset):
start_date_field = 'date_published'
end_date_field = 'date_published_end'
publish_field = 'publish'
@ -120,7 +123,7 @@ class GenericDateQuerySet(TranslatableQuerySet):
return self.active_translations(language_code=language).on_site()
class GenericDateTaggedManager(TaggedFilterItem, TranslationManager):
class GenericDateTaggedManager(TaggedFilterItem, AppHookConfigTranslatableManager):
use_for_related_fields = True
queryset_class = GenericDateQuerySet

View file

@ -3,11 +3,11 @@ from __future__ import absolute_import, print_function, unicode_literals
from cms.menu_bases import CMSAttachMenu
from django.db.models.signals import post_delete, post_save
from django.utils.translation import get_language, ugettext_lazy as _
from django.utils.translation import ugettext_lazy as _, get_language_from_request
from menus.base import Modifier, NavigationNode
from menus.menu_pool import menu_pool
from .models import BlogCategory
from .models import BlogCategory, Post
class BlogCategoryMenu(CMSAttachMenu):
@ -15,54 +15,42 @@ class BlogCategoryMenu(CMSAttachMenu):
def get_nodes(self, request):
nodes = []
qs = BlogCategory.objects.translated(get_language())
qs = qs.order_by('parent__id', 'translations__name')
for category in qs:
language = get_language_from_request(request, check_path=True)
categories = BlogCategory.objects
if hasattr(self, 'instance') and self.instance:
categories = categories.namespace(self.instance.application_namespace)
categories = categories.active_translations(language).distinct()
categories = categories.order_by('parent__id', 'translations__name')
for category in categories:
node = NavigationNode(
category.name,
category.get_absolute_url(),
category.pk,
category.parent_id
'%s-%s' % (category.__class__.__name__, category.pk),
('%s-%s' % (category.__class__.__name__, category.parent.id) if category.parent
else None)
)
nodes.append(node)
posts = Post.objects
if hasattr(self, 'instance') and self.instance:
posts = posts.namespace(self.instance.application_namespace)
posts = posts.active_translations(language).distinct()
for post in posts:
category = post.categories.first()
node = NavigationNode(
post.get_title(),
post.get_absolute_url(language),
'%s-%s' % (post.__class__.__name__, category.pk),
'%s-%s' % (category.__class__.__name__, category.pk)
)
nodes.append(node)
return nodes
menu_pool.register_menu(BlogCategoryMenu)
class BlogNavModifier(Modifier):
"""
This navigation modifier makes sure that when
a particular blog post is viewed,
a corresponding category is selected in menu
"""
def modify(self, request, nodes, namespace, root_id, post_cut, breadcrumb):
if post_cut:
return nodes
if not hasattr(request, 'toolbar'):
return nodes
models = ('djangocms_blog.post', 'djangocms_blog.blogcategory')
model = request.toolbar.get_object_model()
if model not in models:
return nodes
if model == 'djangocms_blog.blogcategory':
cat = request.toolbar.obj
else:
cat = request.toolbar.obj.categories.first()
if not cat:
return nodes
for node in nodes:
if (node.namespace.startswith(BlogCategoryMenu.__name__) and
cat.pk == node.id):
node.selected = True
# no break here because django-cms maintains two menu structures
# for every apphook (attached to published page and draft page)
return nodes
menu_pool.register_modifier(BlogNavModifier)
def clear_menu_cache(**kwargs):
menu_pool.clear(all=True)

View file

@ -0,0 +1,118 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
import aldryn_apphooks_config.fields
import app_data.fields
import djangocms_text_ckeditor.fields
from cms.models import Page
from cms.utils.conf import get_languages
from django.db import models, migrations
def forwards(apps, schema_editor):
BlogConfig = apps.get_model('djangocms_blog', 'BlogConfig')
Post = apps.get_model('djangocms_blog', 'Post')
BlogCategory = apps.get_model('djangocms_blog', 'BlogCategory')
GenericBlogPlugin = apps.get_model('djangocms_blog', 'GenericBlogPlugin')
LatestPostsPlugin = apps.get_model('djangocms_blog', 'LatestPostsPlugin')
AuthorEntriesPlugin = apps.get_model('djangocms_blog', 'AuthorEntriesPlugin')
config = None
for page in Page.objects.drafts().filter(application_urls='BlogApp'):
config = BlogConfig.objects.create(namespace=page.application_namespace)
for lang in get_languages():
config.create_translation(lang, app_title='Blog')
if config:
for model in (Post, BlogCategory, GenericBlogPlugin, LatestPostsPlugin, AuthorEntriesPlugin):
for item in model.objects.all():
item.app_config = config
item.save()
def backwards(apps, schema_editor):
# No need for backward data migration
pass
class Migration(migrations.Migration):
dependencies = [
('cms', '__latest__'),
('djangocms_blog', '0009_latestpostsplugin_tags_new'),
]
operations = [
migrations.CreateModel(
name='BlogConfig',
fields=[
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
('type', models.CharField(verbose_name='type', max_length=100)),
('namespace', models.CharField(default=None, verbose_name='instance namespace', unique=True, max_length=100)),
('app_data', app_data.fields.AppDataField(editable=False, default='{}')),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='BlogConfigTranslation',
fields=[
('id', models.AutoField(auto_created=True, verbose_name='ID', serialize=False, primary_key=True)),
('language_code', models.CharField(db_index=True, verbose_name='Language', max_length=15)),
('app_title', models.CharField(verbose_name='application title', max_length=234)),
('master', models.ForeignKey(editable=False, to='djangocms_blog.BlogConfig', related_name='translations', null=True)),
],
options={
'verbose_name': 'blog config Translation',
'db_table': 'djangocms_blog_blogconfig_translation',
'default_permissions': (),
'db_tablespace': '',
'managed': True,
},
),
migrations.CreateModel(
name='GenericBlogPlugin',
fields=[
('cmsplugin_ptr', models.OneToOneField(parent_link=True, serialize=False, primary_key=True, auto_created=True, to='cms.CMSPlugin')),
('app_config', aldryn_apphooks_config.fields.AppHookConfigField(verbose_name='app. config', blank=True, to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default')),
],
options={
'abstract': False,
},
bases=('cms.cmsplugin',),
),
migrations.AlterField(
model_name='posttranslation',
name='abstract',
field=djangocms_text_ckeditor.fields.HTMLField(default='', verbose_name='abstract', blank=True),
),
migrations.AddField(
model_name='authorentriesplugin',
name='app_config',
field=aldryn_apphooks_config.fields.AppHookConfigField(default=None, blank=True, verbose_name='app. config', to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default'),
preserve_default=False,
),
migrations.AddField(
model_name='blogcategory',
name='app_config',
field=aldryn_apphooks_config.fields.AppHookConfigField(default=None, verbose_name='app. config', to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default'),
preserve_default=False,
),
migrations.AddField(
model_name='latestpostsplugin',
name='app_config',
field=aldryn_apphooks_config.fields.AppHookConfigField(default=None, blank=True, verbose_name='app. config', to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default'),
preserve_default=False,
),
migrations.AddField(
model_name='post',
name='app_config',
field=aldryn_apphooks_config.fields.AppHookConfigField(default=None, verbose_name='app. config', to='djangocms_blog.BlogConfig', help_text='When selecting a value, the form is reloaded to get the updated default'),
preserve_default=False,
),
migrations.AlterUniqueTogether(
name='blogconfigtranslation',
unique_together=set([('language_code', 'master')]),
),
migrations.RunPython(forwards, backwards)
]

View file

@ -1,6 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
from aldryn_apphooks_config.managers.parler import AppHookConfigTranslatableManager
from aldryn_apphooks_config.fields import AppHookConfigField
from cms.models import CMSPlugin, PlaceholderField
from django.conf import settings as dj_settings
from django.core.urlresolvers import reverse
@ -13,10 +15,10 @@ from django.utils.translation import get_language, ugettext_lazy as _
from djangocms_text_ckeditor.fields import HTMLField
from filer.fields.image import FilerImageField
from meta_mixin.models import ModelMeta
from parler.managers import TranslationManager
from parler.models import TranslatableModel, TranslatedFields
from taggit_autosuggest.managers import TaggableManager
from .cms_appconfig import BlogConfig
from .managers import GenericDateTaggedManager
from .settings import get_setting
@ -28,10 +30,10 @@ class BlogCategory(TranslatableModel):
"""
Blog category
"""
parent = models.ForeignKey('self', verbose_name=_('parent'), null=True,
blank=True)
parent = models.ForeignKey('self', verbose_name=_('parent'), null=True, blank=True)
date_created = models.DateTimeField(_('created at'), auto_now_add=True)
date_modified = models.DateTimeField(_('modified at'), auto_now=True)
app_config = AppHookConfigField(BlogConfig, verbose_name=_('app. config'))
translations = TranslatedFields(
name=models.CharField(_('name'), max_length=255),
@ -39,7 +41,7 @@ class BlogCategory(TranslatableModel):
meta={'unique_together': (('language_code', 'slug'),)}
)
objects = TranslationManager()
objects = AppHookConfigTranslatableManager()
class Meta:
verbose_name = _('blog category')
@ -47,16 +49,23 @@ class BlogCategory(TranslatableModel):
@property
def count(self):
return self.blog_posts.published().count()
return self.blog_posts.namespace(self.app_config.namespace).published().count()
def get_absolute_url(self):
lang = get_language()
if self.has_translation(lang):
def get_absolute_url(self, lang=None):
if not lang:
lang = get_language()
if self.has_translation(lang, ):
slug = self.safe_translation_getter('slug', language_code=lang)
return reverse('djangocms_blog:posts-category', kwargs={'category': slug})
return reverse(
'%s:posts-category' % self.app_config.namespace,
kwargs={'category': slug},
current_app=self.app_config.namespace
)
# in case category doesn't exist in this language, gracefully fallback
# to posts-latest
return reverse('djangocms_blog:posts-latest')
return reverse(
'%s:posts-latest' % self.app_config.namespace, current_app=self.app_config.namespace
)
def __str__(self):
return self.safe_translation_getter('name')
@ -108,6 +117,7 @@ class Post(ModelMeta, TranslatableModel):
help_text=_('Select sites in which to show the post. '
u'If none is set it will be '
u'visible in all the configured sites.'))
app_config = AppHookConfigField(BlogConfig, verbose_name=_('app. config'))
translations = TranslatedFields(
title=models.CharField(_('title'), max_length=255),
@ -165,19 +175,21 @@ class Post(ModelMeta, TranslatableModel):
def __str__(self):
return self.safe_translation_getter('title')
def get_absolute_url(self):
def get_absolute_url(self, lang=None):
if not lang:
lang = get_language()
kwargs = {'year': self.date_published.year,
'month': '%02d' % self.date_published.month,
'day': '%02d' % self.date_published.day,
'slug': self.safe_translation_getter('slug',
language_code=get_language(),
language_code=lang,
any_language=True)}
return reverse('djangocms_blog:post-detail', kwargs=kwargs)
return reverse('%s:post-detail' % self.app_config.namespace, kwargs=kwargs)
def save(self, *args, **kwargs):
if not self.slug and self.title:
self.slug = slugify(self.title)
super(Post, self).save(*args, **kwargs)
def save_translation(self, translation, *args, **kwargs):
if not translation.slug and translation.title:
translation.slug = slugify(translation.title)
super(Post, self).save_translation(translation, *args, **kwargs)
def get_title(self):
title = self.safe_translation_getter('meta_title', any_language=True)
@ -230,7 +242,10 @@ class BasePostPlugin(CMSPlugin):
def post_queryset(self, request=None):
language = get_language()
posts = Post._default_manager.active_translations(language_code=language)
posts = Post._default_manager
if self.app_config:
posts = posts.namespace(self.app_config.namespace)
posts = posts.active_translations(language_code=language)
if not request or not getattr(request, 'toolbar', False) or not request.toolbar.edit_mode:
posts = posts.published()
return posts
@ -240,7 +255,7 @@ class BasePostPlugin(CMSPlugin):
class LatestPostsPlugin(BasePostPlugin):
app_config = AppHookConfigField(BlogConfig, verbose_name=_('app. config'), blank=True)
latest_posts = models.IntegerField(_('articles'), default=get_setting('LATEST_POSTS'),
help_text=_('The number of latests '
u'articles to be displayed.'))
@ -269,6 +284,7 @@ class LatestPostsPlugin(BasePostPlugin):
class AuthorEntriesPlugin(BasePostPlugin):
app_config = AppHookConfigField(BlogConfig, verbose_name=_('app. config'), blank=True)
authors = models.ManyToManyField(
dj_settings.AUTH_USER_MODEL, verbose_name=_('authors'),
limit_choices_to={'djangocms_blog_post_author__publish': True}
@ -292,6 +308,17 @@ class AuthorEntriesPlugin(BasePostPlugin):
authors = self.authors.all()
for author in authors:
author.count = 0
if author.djangocms_blog_post_author.filter(publish=True).exists():
author.count = author.djangocms_blog_post_author.filter(publish=True).count()
qs = author.djangocms_blog_post_author
if self.app_config:
qs = qs.namespace(self.app_config.namespace)
count = qs.filter(publish=True).count()
if count:
author.count = count
return authors
class GenericBlogPlugin(BasePostPlugin):
app_config = AppHookConfigField(BlogConfig, verbose_name=_('app. config'), blank=True)
def __str__(self):
return _('generic blog plugin')

View file

@ -52,5 +52,6 @@ def get_setting(name):
'BLOG_USE_PLACEHOLDER': getattr(settings, 'BLOG_USE_PLACEHOLDER', True),
'BLOG_MULTISITE': getattr(settings, 'BLOG_MULTISITE', True),
'BLOG_AUTHOR_DEFAULT': getattr(settings, 'BLOG_AUTHOR_DEFAULT', True),
'BLOG_DEFAULT_PUBLISHED': getattr(settings, 'BLOG_DEFAULT_PUBLISHED', False),
}
return default['BLOG_%s' % name]

View file

@ -0,0 +1,286 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'BlogConfigTranslation'
db.create_table('djangocms_blog_blogconfig_translation', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('language_code', self.gf('django.db.models.fields.CharField')(db_index=True, max_length=15)),
('app_title', self.gf('django.db.models.fields.CharField')(max_length=234)),
('master', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['djangocms_blog.BlogConfig'], related_name='translations', null=True)),
))
db.send_create_signal('djangocms_blog', ['BlogConfigTranslation'])
# Adding unique constraint on 'BlogConfigTranslation', fields ['language_code', 'master']
db.create_unique('djangocms_blog_blogconfig_translation', ['language_code', 'master_id'])
# Adding model 'BlogConfig'
db.create_table('djangocms_blog_blogconfig', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('type', self.gf('django.db.models.fields.CharField')(max_length=100)),
('namespace', self.gf('django.db.models.fields.CharField')(default=None, max_length=100, unique=True)),
('app_data', self.gf('app_data.fields.AppDataField')(default='{}')),
))
db.send_create_signal('djangocms_blog', ['BlogConfig'])
# Adding model 'GenericBlogPlugin'
db.create_table('djangocms_blog_genericblogplugin', (
('cmsplugin_ptr', self.gf('django.db.models.fields.related.OneToOneField')(primary_key=True, to=orm['cms.CMSPlugin'], unique=True)),
('app_config', self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(blank=True, null=True, to=orm['djangocms_blog.BlogConfig'])),
))
db.send_create_signal('djangocms_blog', ['GenericBlogPlugin'])
# Adding field 'AuthorEntriesPlugin.app_config'
db.add_column('djangocms_blog_authorentriesplugin', 'app_config',
self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(default=None, blank=True, null=True, to=orm['djangocms_blog.BlogConfig']),
keep_default=False)
# Adding field 'Post.app_config'
db.add_column('djangocms_blog_post', 'app_config',
self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(to=orm['djangocms_blog.BlogConfig'], null=True, default=None),
keep_default=False)
# Adding field 'BlogCategory.app_config'
db.add_column('djangocms_blog_blogcategory', 'app_config',
self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(to=orm['djangocms_blog.BlogConfig'], null=True, default=None),
keep_default=False)
# Adding field 'LatestPostsPlugin.app_config'
db.add_column('djangocms_blog_latestpostsplugin', 'app_config',
self.gf('aldryn_apphooks_config.fields.AppHookConfigField')(default=None, null=True, blank=True, to=orm['djangocms_blog.BlogConfig']),
keep_default=False)
def backwards(self, orm):
# Removing unique constraint on 'BlogConfigTranslation', fields ['language_code', 'master']
db.delete_unique('djangocms_blog_blogconfig_translation', ['language_code', 'master_id'])
# Deleting model 'BlogConfigTranslation'
db.delete_table('djangocms_blog_blogconfig_translation')
# Deleting model 'BlogConfig'
db.delete_table('djangocms_blog_blogconfig')
# Deleting model 'GenericBlogPlugin'
db.delete_table('djangocms_blog_genericblogplugin')
# Deleting field 'AuthorEntriesPlugin.app_config'
db.delete_column('djangocms_blog_authorentriesplugin', 'app_config_id')
# Deleting field 'Post.app_config'
db.delete_column('djangocms_blog_post', 'app_config_id')
# Deleting field 'BlogCategory.app_config'
db.delete_column('djangocms_blog_blogcategory', 'app_config_id')
# Deleting field 'LatestPostsPlugin.app_config'
db.delete_column('djangocms_blog_latestpostsplugin', 'app_config_id')
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['auth.Permission']"})
},
'auth.permission': {
'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission', 'ordering': "('content_type__app_label', 'content_type__model', 'codename')"},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'blank': 'True', 'max_length': '75'}),
'first_name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '30'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'related_name': "'user_set'", 'to': "orm['auth.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '30'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'related_name': "'user_set'", 'to': "orm['auth.Permission']"}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '30', 'unique': 'True'})
},
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'changed_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'depth': ('django.db.models.fields.PositiveIntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '15'}),
'numchild': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'to': "orm['cms.CMSPlugin']", 'null': 'True'}),
'path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'blank': 'True', 'null': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255'})
},
'cmsplugin_filer_image.thumbnailoption': {
'Meta': {'object_name': 'ThumbnailOption', 'ordering': "('width', 'height')"},
'crop': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'height': ('django.db.models.fields.IntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'upscale': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'width': ('django.db.models.fields.IntegerField', [], {})
},
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", 'ordering': "('name',)", 'db_table': "'django_content_type'", 'object_name': 'ContentType'},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'djangocms_blog.authorentriesplugin': {
'Meta': {'object_name': 'AuthorEntriesPlugin'},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'blank': 'True', 'to': "orm['djangocms_blog.BlogConfig']"}),
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.User']"}),
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'primary_key': 'True', 'to': "orm['cms.CMSPlugin']", 'unique': 'True'}),
'latest_posts': ('django.db.models.fields.IntegerField', [], {'default': '5'})
},
'djangocms_blog.blogcategory': {
'Meta': {'object_name': 'BlogCategory'},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': "orm['djangocms_blog.BlogConfig']"}),
'date_created': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'date_modified': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'to': "orm['djangocms_blog.BlogCategory']", 'null': 'True'})
},
'djangocms_blog.blogcategorytranslation': {
'Meta': {'unique_together': "[('language_code', 'slug'), ('language_code', 'master')]", 'object_name': 'BlogCategoryTranslation', 'db_table': "'djangocms_blog_blogcategory_translation'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language_code': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '15'}),
'master': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djangocms_blog.BlogCategory']", 'related_name': "'translations'", 'null': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'slug': ('django.db.models.fields.SlugField', [], {'blank': 'True', 'max_length': '50'})
},
'djangocms_blog.blogconfig': {
'Meta': {'object_name': 'BlogConfig'},
'app_data': ('app_data.fields.AppDataField', [], {'default': "'{}'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'namespace': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '100', 'unique': 'True'}),
'paginate_by': ('django.db.models.fields.PositiveIntegerField', [], {'default': '10'}),
'set_author': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'djangocms_blog.blogconfigtranslation': {
'Meta': {'unique_together': "[('language_code', 'master')]", 'object_name': 'BlogConfigTranslation', 'db_table': "'djangocms_blog_blogconfig_translation'"},
'app_title': ('django.db.models.fields.CharField', [], {'max_length': '234'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language_code': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '15'}),
'master': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djangocms_blog.BlogConfig']", 'related_name': "'translations'", 'null': 'True'})
},
'djangocms_blog.genericblogplugin': {
'Meta': {'object_name': 'GenericBlogPlugin'},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'blank': 'True', 'to': "orm['djangocms_blog.BlogConfig']"}),
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'primary_key': 'True', 'to': "orm['cms.CMSPlugin']", 'unique': 'True'})
},
'djangocms_blog.latestpostsplugin': {
'Meta': {'object_name': 'LatestPostsPlugin'},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'blank': 'True', 'to': "orm['djangocms_blog.BlogConfig']"}),
'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['djangocms_blog.BlogCategory']"}),
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'primary_key': 'True', 'to': "orm['cms.CMSPlugin']", 'unique': 'True'}),
'latest_posts': ('django.db.models.fields.IntegerField', [], {'default': '5'})
},
'djangocms_blog.post': {
'Meta': {'object_name': 'Post', 'ordering': "('-date_published', '-date_created')"},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': "orm['djangocms_blog.BlogConfig']"}),
'author': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'djangocms_blog_post_author'", 'to': "orm['auth.User']", 'null': 'True'}),
'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['djangocms_blog.BlogCategory']", 'related_name': "'blog_posts'"}),
'content': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'related_name': "'post_content'", 'null': 'True'}),
'date_created': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'date_modified': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'date_published': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'date_published_end': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'null': 'True'}),
'enable_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'main_image': ('django.db.models.fields.related.ForeignKey', [], {'on_delete': 'models.SET_NULL', 'blank': 'True', 'related_name': "'djangocms_blog_post_image'", 'to': "orm['filer.Image']", 'null': 'True'}),
'main_image_full': ('django.db.models.fields.related.ForeignKey', [], {'on_delete': 'models.SET_NULL', 'blank': 'True', 'related_name': "'djangocms_blog_post_full'", 'to': "orm['cmsplugin_filer_image.ThumbnailOption']", 'null': 'True'}),
'main_image_thumbnail': ('django.db.models.fields.related.ForeignKey', [], {'on_delete': 'models.SET_NULL', 'blank': 'True', 'related_name': "'djangocms_blog_post_thumbnail'", 'to': "orm['cmsplugin_filer_image.ThumbnailOption']", 'null': 'True'}),
'publish': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['sites.Site']", 'null': 'True'})
},
'djangocms_blog.posttranslation': {
'Meta': {'unique_together': "[('language_code', 'slug'), ('language_code', 'master')]", 'object_name': 'PostTranslation', 'db_table': "'djangocms_blog_post_translation'"},
'abstract': ('djangocms_text_ckeditor.fields.HTMLField', [], {'blank': 'True', 'default': "''"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language_code': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '15'}),
'master': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djangocms_blog.Post']", 'related_name': "'translations'", 'null': 'True'}),
'meta_description': ('django.db.models.fields.TextField', [], {'blank': 'True', 'default': "''"}),
'meta_keywords': ('django.db.models.fields.TextField', [], {'blank': 'True', 'default': "''"}),
'meta_title': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'default': "''"}),
'post_text': ('djangocms_text_ckeditor.fields.HTMLField', [], {'blank': 'True', 'default': "''"}),
'slug': ('django.db.models.fields.SlugField', [], {'blank': 'True', 'max_length': '50'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
'filer.file': {
'Meta': {'object_name': 'File'},
'_file_size': ('django.db.models.fields.IntegerField', [], {'blank': 'True', 'null': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True', 'null': 'True'}),
'file': ('django.db.models.fields.files.FileField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'folder': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'all_files'", 'to': "orm['filer.Folder']", 'null': 'True'}),
'has_all_mandatory_data': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'modified_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'default': "''"}),
'original_filename': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_files'", 'to': "orm['auth.User']", 'null': 'True'}),
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'related_name': "'polymorphic_filer.file_set+'", 'null': 'True'}),
'sha1': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '40', 'default': "''"}),
'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'})
},
'filer.folder': {
'Meta': {'unique_together': "(('parent', 'name'),)", 'object_name': 'Folder', 'ordering': "('name',)"},
'created_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'modified_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'filer_owned_folders'", 'to': "orm['auth.User']", 'null': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'to': "orm['filer.Folder']", 'null': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'})
},
'filer.image': {
'Meta': {'object_name': 'Image'},
'_height': ('django.db.models.fields.IntegerField', [], {'blank': 'True', 'null': 'True'}),
'_width': ('django.db.models.fields.IntegerField', [], {'blank': 'True', 'null': 'True'}),
'author': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'date_taken': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'null': 'True'}),
'default_alt_text': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'default_caption': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'file_ptr': ('django.db.models.fields.related.OneToOneField', [], {'primary_key': 'True', 'to': "orm['filer.File']", 'unique': 'True'}),
'must_always_publish_author_credit': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'must_always_publish_copyright': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'subject_location': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '64', 'default': 'None', 'null': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'db_table': "'django_site'", 'object_name': 'Site'},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
}
}
complete_apps = ['djangocms_blog']

View file

@ -0,0 +1,234 @@
# -*- coding: utf-8 -*-
from south.utils import datetime_utils as datetime
from south.db import db
from south.v2 import DataMigration
from django.db import models
from cms.models import Page
from cms.utils.conf import get_languages
class Migration(DataMigration):
def forwards(self, orm):
BlogConfig = orm['djangocms_blog.BlogConfig']
Post = orm['djangocms_blog.Post']
BlogCategory = orm['djangocms_blog.BlogCategory']
GenericBlogPlugin = orm['djangocms_blog.GenericBlogPlugin']
LatestPostsPlugin = orm['djangocms_blog.LatestPostsPlugin']
AuthorEntriesPlugin = orm['djangocms_blog.AuthorEntriesPlugin']
config = None
for page in Page.objects.drafts().filter(application_urls='BlogApp'):
config = BlogConfig.objects.create(namespace=page.application_namespace)
for lang in get_languages():
config.create_translation(lang, app_title='Blog')
if config:
for model in (Post, BlogCategory, GenericBlogPlugin, LatestPostsPlugin, AuthorEntriesPlugin):
for item in model.objects.all():
item.app_config = config
item.save()
def backwards(self, orm):
# No need for backward data migration
pass
models = {
'auth.group': {
'Meta': {'object_name': 'Group'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '80', 'unique': 'True'}),
'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['auth.Permission']"})
},
'auth.permission': {
'Meta': {'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission', 'ordering': "('content_type__app_label', 'content_type__model', 'codename')"},
'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
},
'auth.user': {
'Meta': {'object_name': 'User'},
'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'email': ('django.db.models.fields.EmailField', [], {'blank': 'True', 'max_length': '75'}),
'first_name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '30'}),
'groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'related_name': "'user_set'", 'to': "orm['auth.Group']"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'last_name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '30'}),
'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'related_name': "'user_set'", 'to': "orm['auth.Permission']"}),
'username': ('django.db.models.fields.CharField', [], {'max_length': '30', 'unique': 'True'})
},
'cms.cmsplugin': {
'Meta': {'object_name': 'CMSPlugin'},
'changed_date': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'creation_date': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'depth': ('django.db.models.fields.PositiveIntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '15'}),
'numchild': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'to': "orm['cms.CMSPlugin']", 'null': 'True'}),
'path': ('django.db.models.fields.CharField', [], {'max_length': '255', 'unique': 'True'}),
'placeholder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'null': 'True'}),
'plugin_type': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '50'}),
'position': ('django.db.models.fields.PositiveSmallIntegerField', [], {'blank': 'True', 'null': 'True'})
},
'cms.placeholder': {
'Meta': {'object_name': 'Placeholder'},
'default_width': ('django.db.models.fields.PositiveSmallIntegerField', [], {'null': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'slot': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '255'})
},
'cmsplugin_filer_image.thumbnailoption': {
'Meta': {'object_name': 'ThumbnailOption', 'ordering': "('width', 'height')"},
'crop': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'height': ('django.db.models.fields.IntegerField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'upscale': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'width': ('django.db.models.fields.IntegerField', [], {})
},
'contenttypes.contenttype': {
'Meta': {'unique_together': "(('app_label', 'model'),)", 'ordering': "('name',)", 'db_table': "'django_content_type'", 'object_name': 'ContentType'},
'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'djangocms_blog.authorentriesplugin': {
'Meta': {'object_name': 'AuthorEntriesPlugin'},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'blank': 'True', 'to': "orm['djangocms_blog.BlogConfig']"}),
'authors': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['auth.User']"}),
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'primary_key': 'True', 'to': "orm['cms.CMSPlugin']", 'unique': 'True'}),
'latest_posts': ('django.db.models.fields.IntegerField', [], {'default': '5'})
},
'djangocms_blog.blogcategory': {
'Meta': {'object_name': 'BlogCategory'},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': "orm['djangocms_blog.BlogConfig']"}),
'date_created': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'date_modified': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'to': "orm['djangocms_blog.BlogCategory']", 'null': 'True'})
},
'djangocms_blog.blogcategorytranslation': {
'Meta': {'unique_together': "[('language_code', 'slug'), ('language_code', 'master')]", 'object_name': 'BlogCategoryTranslation', 'db_table': "'djangocms_blog_blogcategory_translation'"},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language_code': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '15'}),
'master': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djangocms_blog.BlogCategory']", 'related_name': "'translations'", 'null': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'slug': ('django.db.models.fields.SlugField', [], {'blank': 'True', 'max_length': '50'})
},
'djangocms_blog.blogconfig': {
'Meta': {'object_name': 'BlogConfig'},
'app_data': ('app_data.fields.AppDataField', [], {'default': "'{}'"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'namespace': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '100', 'unique': 'True'}),
'paginate_by': ('django.db.models.fields.PositiveIntegerField', [], {'default': '10'}),
'set_author': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'djangocms_blog.blogconfigtranslation': {
'Meta': {'unique_together': "[('language_code', 'master')]", 'object_name': 'BlogConfigTranslation', 'db_table': "'djangocms_blog_blogconfig_translation'"},
'app_title': ('django.db.models.fields.CharField', [], {'max_length': '234'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language_code': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '15'}),
'master': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djangocms_blog.BlogConfig']", 'related_name': "'translations'", 'null': 'True'})
},
'djangocms_blog.genericblogplugin': {
'Meta': {'object_name': 'GenericBlogPlugin'},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'blank': 'True', 'to': "orm['djangocms_blog.BlogConfig']"}),
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'primary_key': 'True', 'to': "orm['cms.CMSPlugin']", 'unique': 'True'})
},
'djangocms_blog.latestpostsplugin': {
'Meta': {'object_name': 'LatestPostsPlugin'},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'blank': 'True', 'to': "orm['djangocms_blog.BlogConfig']"}),
'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['djangocms_blog.BlogCategory']"}),
'cmsplugin_ptr': ('django.db.models.fields.related.OneToOneField', [], {'primary_key': 'True', 'to': "orm['cms.CMSPlugin']", 'unique': 'True'}),
'latest_posts': ('django.db.models.fields.IntegerField', [], {'default': '5'})
},
'djangocms_blog.post': {
'Meta': {'object_name': 'Post', 'ordering': "('-date_published', '-date_created')"},
'app_config': ('aldryn_apphooks_config.fields.AppHookConfigField', [], {'to': "orm['djangocms_blog.BlogConfig']"}),
'author': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'djangocms_blog_post_author'", 'to': "orm['auth.User']", 'null': 'True'}),
'categories': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['djangocms_blog.BlogCategory']", 'related_name': "'blog_posts'"}),
'content': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['cms.Placeholder']", 'related_name': "'post_content'", 'null': 'True'}),
'date_created': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'date_modified': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'date_published': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
'date_published_end': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'null': 'True'}),
'enable_comments': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'main_image': ('django.db.models.fields.related.ForeignKey', [], {'on_delete': 'models.SET_NULL', 'blank': 'True', 'related_name': "'djangocms_blog_post_image'", 'to': "orm['filer.Image']", 'null': 'True'}),
'main_image_full': ('django.db.models.fields.related.ForeignKey', [], {'on_delete': 'models.SET_NULL', 'blank': 'True', 'related_name': "'djangocms_blog_post_full'", 'to': "orm['cmsplugin_filer_image.ThumbnailOption']", 'null': 'True'}),
'main_image_thumbnail': ('django.db.models.fields.related.ForeignKey', [], {'on_delete': 'models.SET_NULL', 'blank': 'True', 'related_name': "'djangocms_blog_post_thumbnail'", 'to': "orm['cmsplugin_filer_image.ThumbnailOption']", 'null': 'True'}),
'publish': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'sites': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'blank': 'True', 'to': "orm['sites.Site']", 'null': 'True'})
},
'djangocms_blog.posttranslation': {
'Meta': {'unique_together': "[('language_code', 'slug'), ('language_code', 'master')]", 'object_name': 'PostTranslation', 'db_table': "'djangocms_blog_post_translation'"},
'abstract': ('djangocms_text_ckeditor.fields.HTMLField', [], {'blank': 'True', 'default': "''"}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'language_code': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '15'}),
'master': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['djangocms_blog.Post']", 'related_name': "'translations'", 'null': 'True'}),
'meta_description': ('django.db.models.fields.TextField', [], {'blank': 'True', 'default': "''"}),
'meta_keywords': ('django.db.models.fields.TextField', [], {'blank': 'True', 'default': "''"}),
'meta_title': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'default': "''"}),
'post_text': ('djangocms_text_ckeditor.fields.HTMLField', [], {'blank': 'True', 'default': "''"}),
'slug': ('django.db.models.fields.SlugField', [], {'blank': 'True', 'max_length': '50'}),
'title': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
'filer.file': {
'Meta': {'object_name': 'File'},
'_file_size': ('django.db.models.fields.IntegerField', [], {'blank': 'True', 'null': 'True'}),
'description': ('django.db.models.fields.TextField', [], {'blank': 'True', 'null': 'True'}),
'file': ('django.db.models.fields.files.FileField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'folder': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'all_files'", 'to': "orm['filer.Folder']", 'null': 'True'}),
'has_all_mandatory_data': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'is_public': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
'modified_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'default': "''"}),
'original_filename': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'owned_files'", 'to': "orm['auth.User']", 'null': 'True'}),
'polymorphic_ctype': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']", 'related_name': "'polymorphic_filer.file_set+'", 'null': 'True'}),
'sha1': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '40', 'default': "''"}),
'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'})
},
'filer.folder': {
'Meta': {'unique_together': "(('parent', 'name'),)", 'object_name': 'Folder', 'ordering': "('name',)"},
'created_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'level': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'lft': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'modified_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'filer_owned_folders'", 'to': "orm['auth.User']", 'null': 'True'}),
'parent': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'children'", 'to': "orm['filer.Folder']", 'null': 'True'}),
'rght': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'tree_id': ('django.db.models.fields.PositiveIntegerField', [], {'db_index': 'True'}),
'uploaded_at': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'auto_now_add': 'True'})
},
'filer.image': {
'Meta': {'object_name': 'Image'},
'_height': ('django.db.models.fields.IntegerField', [], {'blank': 'True', 'null': 'True'}),
'_width': ('django.db.models.fields.IntegerField', [], {'blank': 'True', 'null': 'True'}),
'author': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'date_taken': ('django.db.models.fields.DateTimeField', [], {'blank': 'True', 'null': 'True'}),
'default_alt_text': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'default_caption': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '255', 'null': 'True'}),
'file_ptr': ('django.db.models.fields.related.OneToOneField', [], {'primary_key': 'True', 'to': "orm['filer.File']", 'unique': 'True'}),
'must_always_publish_author_credit': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'must_always_publish_copyright': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'subject_location': ('django.db.models.fields.CharField', [], {'blank': 'True', 'max_length': '64', 'default': 'None', 'null': 'True'})
},
'sites.site': {
'Meta': {'ordering': "('domain',)", 'db_table': "'django_site'", 'object_name': 'Site'},
'domain': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
}
}
complete_apps = ['djangocms_blog']

View file

@ -21,7 +21,7 @@
</div>
{% endif %}
{% endspaceless %}
{% if use_placeholder %}
{% if post.app_config.use_placeholder %}
<div class="blog-content">{% render_placeholder post.content %}</div>
{% else %}
<div class="blog-content">{% render_model post "post_text" "post_text" %}</div>

View file

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import, print_function, unicode_literals
from aldryn_apphooks_config.mixins import AppConfigMixin
from django.contrib.auth import get_user_model
from django.core.urlresolvers import resolve
from django.utils.timezone import now
from django.utils.translation import get_language
from django.views.generic import DetailView, ListView
@ -14,25 +14,24 @@ from .settings import get_setting
User = get_user_model()
class BaseBlogView(ViewUrlMixin):
class BaseBlogView(AppConfigMixin, ViewUrlMixin):
def get_queryset(self):
language = get_language()
queryset = self.model._default_manager.all().active_translations(language_code=language)
queryset = self.model._default_manager.namespace(
self.namespace
).active_translations(
language_code=language
)
if not getattr(self.request, 'toolbar', False) or not self.request.toolbar.edit_mode:
queryset = queryset.published()
return queryset
def render_to_response(self, context, **response_kwargs):
response_kwargs['current_app'] = resolve(self.request.path).namespace
return super(BaseBlogView, self).render_to_response(context, **response_kwargs)
class PostListView(BaseBlogView, ListView):
model = Post
context_object_name = 'post_list'
template_name = 'djangocms_blog/post_list.html'
paginate_by = get_setting('PAGINATION')
view_url_name = 'djangocms_blog:posts-latest'
def get_context_data(self, **kwargs):
@ -40,6 +39,9 @@ class PostListView(BaseBlogView, ListView):
context['TRUNCWORDS_COUNT'] = get_setting('POSTS_LIST_TRUNCWORDS_COUNT')
return context
def get_paginate_by(self, queryset):
return self.config.paginate_by
class PostDetailView(TranslatableSlugMixin, BaseBlogView, DetailView):
model = Post