djangocms_blog/djangocms_blog/models.py

358 lines
14 KiB
Python
Raw Normal View History

2014-01-04 16:07:09 +00:00
# -*- coding: utf-8 -*-
2015-09-12 22:46:05 +00:00
from __future__ import absolute_import, print_function, unicode_literals
2015-09-19 23:11:14 +00:00
from aldryn_apphooks_config.fields import AppHookConfigField
2015-09-07 07:18:17 +00:00
from aldryn_apphooks_config.managers.parler import AppHookConfigTranslatableManager
2015-07-18 15:33:36 +00:00
from cms.models import CMSPlugin, PlaceholderField
2014-09-04 07:16:56 +00:00
from django.conf import settings as dj_settings
2014-01-04 16:07:09 +00:00
from django.core.urlresolvers import reverse
from django.db import models
from django.utils import timezone
2014-10-16 15:40:25 +00:00
from django.utils.encoding import force_text, python_2_unicode_compatible
2015-07-18 15:33:36 +00:00
from django.utils.html import escape, strip_tags
2014-01-04 16:07:09 +00:00
from django.utils.text import slugify
2015-09-12 22:33:13 +00:00
from django.utils.translation import get_language, ugettext_lazy as _
2014-01-04 16:07:09 +00:00
from djangocms_text_ckeditor.fields import HTMLField
from filer.fields.image import FilerImageField
2014-10-02 12:50:53 +00:00
from meta_mixin.models import ModelMeta
2015-07-18 15:33:36 +00:00
from parler.models import TranslatableModel, TranslatedFields
2014-01-04 16:07:09 +00:00
from taggit_autosuggest.managers import TaggableManager
2015-09-19 23:11:14 +00:00
from .cms_appconfig import BlogConfig
from .managers import GenericDateTaggedManager
2015-07-18 15:33:36 +00:00
from .settings import get_setting
2014-01-04 16:07:09 +00:00
BLOG_CURRENT_POST_IDENTIFIER = 'djangocms_post_current'
2015-09-30 07:34:11 +00:00
BLOG_CURRENT_NAMESPACE = 'djangocms_post_current_config'
2014-01-04 16:07:09 +00:00
2014-10-16 15:40:25 +00:00
@python_2_unicode_compatible
2014-01-04 16:07:09 +00:00
class BlogCategory(TranslatableModel):
"""
Blog category
"""
2015-09-19 23:11:14 +00:00
parent = models.ForeignKey('self', verbose_name=_('parent'), null=True, blank=True)
2014-01-04 16:07:09 +00:00
date_created = models.DateTimeField(_('created at'), auto_now_add=True)
date_modified = models.DateTimeField(_('modified at'), auto_now=True)
2015-09-30 08:03:02 +00:00
app_config = AppHookConfigField(
BlogConfig, null=True, verbose_name=_('app. config')
)
2014-01-04 16:07:09 +00:00
translations = TranslatedFields(
name=models.CharField(_('name'), max_length=255),
slug=models.SlugField(_('slug'), blank=True, db_index=True),
meta={'unique_together': (('language_code', 'slug'),)}
2014-01-04 16:07:09 +00:00
)
2015-09-19 23:11:14 +00:00
objects = AppHookConfigTranslatableManager()
2014-01-04 16:07:09 +00:00
class Meta:
verbose_name = _('blog category')
verbose_name_plural = _('blog categories')
2014-01-08 21:33:20 +00:00
@property
def count(self):
2015-09-19 23:11:14 +00:00
return self.blog_posts.namespace(self.app_config.namespace).published().count()
2014-01-04 16:07:09 +00:00
2015-09-19 23:11:14 +00:00
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)
2015-09-19 23:11:14 +00:00
return reverse(
'%s:posts-category' % self.app_config.namespace,
kwargs={'category': slug},
current_app=self.app_config.namespace
)
2015-07-17 13:57:30 +00:00
# in case category doesn't exist in this language, gracefully fallback
# to posts-latest
2015-09-19 23:11:14 +00:00
return reverse(
'%s:posts-latest' % self.app_config.namespace, current_app=self.app_config.namespace
)
2015-07-17 13:57:30 +00:00
2014-10-16 15:40:25 +00:00
def __str__(self):
return self.safe_translation_getter('name')
2014-01-04 16:07:09 +00:00
def save(self, *args, **kwargs):
super(BlogCategory, self).save(*args, **kwargs)
for lang in self.get_available_languages():
self.set_current_language(lang)
if not self.slug and self.name:
2014-06-08 22:06:12 +00:00
self.slug = slugify(force_text(self.name))
self.save_translations()
2014-01-04 16:07:09 +00:00
2014-10-16 15:40:25 +00:00
@python_2_unicode_compatible
class Post(ModelMeta, TranslatableModel):
2014-01-04 16:07:09 +00:00
"""
Blog post
"""
2014-09-04 07:16:56 +00:00
author = models.ForeignKey(dj_settings.AUTH_USER_MODEL,
2015-09-12 22:46:05 +00:00
verbose_name=_('author'), null=True, blank=True,
2014-04-08 17:10:56 +00:00
related_name='djangocms_blog_post_author')
2014-01-04 16:07:09 +00:00
2015-09-12 22:46:05 +00:00
date_created = models.DateTimeField(_('created'), auto_now_add=True)
date_modified = models.DateTimeField(_('last modified'), auto_now=True)
2015-09-30 07:57:40 +00:00
date_published = models.DateTimeField(_('published since'),
2014-01-04 16:07:09 +00:00
default=timezone.now)
2015-09-30 07:57:40 +00:00
date_published_end = models.DateTimeField(_('published until'), null=True,
2014-01-04 16:07:09 +00:00
blank=True)
2015-09-12 22:46:05 +00:00
publish = models.BooleanField(_('publish'), default=False)
categories = models.ManyToManyField('djangocms_blog.BlogCategory', verbose_name=_('category'),
2014-01-04 16:07:09 +00:00
related_name='blog_posts',)
2015-09-12 22:46:05 +00:00
main_image = FilerImageField(verbose_name=_('main image'), blank=True, null=True,
on_delete=models.SET_NULL,
2014-04-08 17:10:56 +00:00
related_name='djangocms_blog_post_image')
2015-07-19 07:37:26 +00:00
main_image_thumbnail = models.ForeignKey('cmsplugin_filer_image.ThumbnailOption',
2015-09-12 22:46:05 +00:00
verbose_name=_('main image thumbnail'),
2014-04-08 17:10:56 +00:00
related_name='djangocms_blog_post_thumbnail',
on_delete=models.SET_NULL,
2014-01-04 16:07:09 +00:00
blank=True, null=True)
2015-07-19 07:37:26 +00:00
main_image_full = models.ForeignKey('cmsplugin_filer_image.ThumbnailOption',
2015-09-12 22:46:05 +00:00
verbose_name=_('main image full'),
related_name='djangocms_blog_post_full',
on_delete=models.SET_NULL,
2014-01-04 20:13:25 +00:00
blank=True, null=True)
2015-09-12 22:46:05 +00:00
enable_comments = models.BooleanField(verbose_name=_('enable comments on post'),
2015-07-19 07:37:26 +00:00
default=get_setting('ENABLE_COMMENTS'))
2015-09-12 22:46:05 +00:00
sites = models.ManyToManyField('sites.Site', verbose_name=_('Site(s)'), blank=True,
help_text=_('Select sites in which to show the post. '
2015-09-26 08:38:57 +00:00
'If none is set it will be '
'visible in all the configured sites.'))
2015-09-30 08:03:02 +00:00
app_config = AppHookConfigField(
BlogConfig, null=True, verbose_name=_('app. config')
)
2014-01-04 16:07:09 +00:00
translations = TranslatedFields(
2015-09-12 22:46:05 +00:00
title=models.CharField(_('title'), max_length=255),
slug=models.SlugField(_('slug'), blank=True, db_index=True),
abstract=HTMLField(_('abstract'), blank=True, default=''),
meta_description=models.TextField(verbose_name=_('post meta description'),
2014-03-05 17:11:32 +00:00
blank=True, default=''),
2015-09-12 22:46:05 +00:00
meta_keywords=models.TextField(verbose_name=_('post meta keywords'),
2014-03-06 19:02:52 +00:00
blank=True, default=''),
2015-09-12 22:46:05 +00:00
meta_title=models.CharField(verbose_name=_('post meta title'),
help_text=_('used in title tag and social sharing'),
max_length=255,
blank=True, default=''),
2015-09-12 22:46:05 +00:00
post_text=HTMLField(_('text'), default='', blank=True),
meta={'unique_together': (('language_code', 'slug'),)}
2014-01-04 16:07:09 +00:00
)
content = PlaceholderField('post_content', related_name='post_content')
2014-01-04 16:07:09 +00:00
objects = GenericDateTaggedManager()
tags = TaggableManager(blank=True, related_name='djangocms_blog_tags')
2014-01-04 16:07:09 +00:00
_metadata = {
'title': 'get_title',
'description': 'get_description',
2015-09-26 16:01:22 +00:00
'keywords': 'get_keywords',
'og_description': 'get_description',
'twitter_description': 'get_description',
'gplus_description': 'get_description',
'locale': None,
2014-06-15 11:10:06 +00:00
'image': 'get_image_full_url',
2015-09-24 19:51:54 +00:00
'object_type': 'get_meta_attribute',
'og_type': 'get_meta_attribute',
'og_app_id': 'get_meta_attribute',
'og_profile_id': 'get_meta_attribute',
'og_publisher': 'get_meta_attribute',
'og_author_url': 'get_meta_attribute',
2015-08-22 20:35:30 +00:00
'og_author': 'get_meta_attribute',
2015-09-24 19:51:54 +00:00
'twitter_type': 'get_meta_attribute',
'twitter_site': 'get_meta_attribute',
'twitter_author': 'get_meta_attribute',
'gplus_type': 'get_meta_attribute',
'gplus_author': 'get_meta_attribute',
'published_time': 'date_published',
'modified_time': 'date_modified',
'expiration_time': 'date_published_end',
'tag': 'get_tags',
'url': 'get_absolute_url',
}
2015-07-18 21:06:47 +00:00
class Meta:
verbose_name = _('blog article')
verbose_name_plural = _('blog articles')
ordering = ('-date_published', '-date_created')
get_latest_by = 'date_published'
def __str__(self):
return self.safe_translation_getter('title')
2015-09-19 23:11:14 +00:00
def get_absolute_url(self, lang=None):
if not lang:
lang = get_language()
category = self.categories.first()
kwargs = {}
urlconf = get_setting('PERMALINK_URLS')[self.app_config.url_patterns]
if '<year>' in urlconf:
kwargs['year'] = self.date_published.year
if '<month>' in urlconf:
kwargs['month'] = '%02d' % self.date_published.month
if '<day>' in urlconf:
kwargs['day'] = '%02d' % self.date_published.day
if '<slug>' in urlconf:
kwargs['slug'] = self.safe_translation_getter('slug', language_code=lang, any_language=True) # NOQA
if '<category>' in urlconf:
kwargs['category'] = category.safe_translation_getter('slug', language_code=lang, any_language=True) # NOQA
2015-09-19 23:11:14 +00:00
return reverse('%s:post-detail' % self.app_config.namespace, kwargs=kwargs)
2015-07-18 21:06:47 +00:00
2015-09-24 19:51:54 +00:00
def get_meta_attribute(self, param):
"""
Retrieves django-meta attributes from apphook config instance
:param param: django-meta attribute passed as key
"""
attr = None
value = getattr(self.app_config, param)
if value:
attr = getattr(self, value, None)
if attr is not None:
if callable(attr):
try:
data = attr(param)
except TypeError:
data = attr()
else:
data = attr
else:
data = value
return data
2015-09-24 19:51:54 +00:00
2015-09-19 23:11:14 +00:00
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)
2015-07-18 21:06:47 +00:00
def get_title(self):
title = self.safe_translation_getter('meta_title', any_language=True)
if not title:
title = self.safe_translation_getter('title', any_language=True)
return title.strip()
def get_keywords(self):
2014-09-05 06:28:10 +00:00
return self.safe_translation_getter('meta_keywords').strip().split(',')
def get_description(self):
2014-06-08 22:06:12 +00:00
description = self.safe_translation_getter('meta_description', any_language=True)
if not description:
2014-06-08 22:06:12 +00:00
description = self.safe_translation_getter('abstract', any_language=True)
2014-10-16 15:40:25 +00:00
return escape(strip_tags(description)).strip()
2014-06-15 11:10:06 +00:00
def get_image_full_url(self):
2014-06-20 16:28:06 +00:00
if self.main_image:
return self.make_full_url(self.main_image.url)
return ''
def get_tags(self):
taglist = [tag.name for tag in self.tags.all()]
2014-09-05 06:28:10 +00:00
return ','.join(taglist)
def get_author(self):
return self.author
2014-01-04 16:07:09 +00:00
def thumbnail_options(self):
if self.main_image_thumbnail_id:
2014-01-04 20:13:25 +00:00
return self.main_image_thumbnail.as_dict
2014-01-04 16:07:09 +00:00
else:
2014-10-11 10:23:36 +00:00
return get_setting('IMAGE_THUMBNAIL_SIZE')
2014-01-08 21:33:20 +00:00
2014-01-04 16:07:09 +00:00
def full_image_options(self):
2014-06-08 22:06:12 +00:00
if self.main_image_full_id:
2014-01-04 20:13:25 +00:00
return self.main_image_full.as_dict
2014-01-04 16:07:09 +00:00
else:
2014-10-11 10:23:36 +00:00
return get_setting('IMAGE_FULL_SIZE')
2014-01-04 16:07:09 +00:00
def get_full_url(self):
2014-06-15 11:10:06 +00:00
return self.make_full_url(self.get_absolute_url())
2014-01-04 16:07:09 +00:00
2014-10-16 15:40:25 +00:00
@python_2_unicode_compatible
class BasePostPlugin(CMSPlugin):
2015-09-30 08:03:02 +00:00
app_config = AppHookConfigField(
BlogConfig, null=True, verbose_name=_('app. config'), blank=True
)
class Meta:
abstract = True
def post_queryset(self, request=None):
language = get_language()
2015-09-19 23:11:14 +00:00
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
def __str__(self):
return _('generic blog plugin')
class LatestPostsPlugin(BasePostPlugin):
2015-09-12 22:46:05 +00:00
latest_posts = models.IntegerField(_('articles'), default=get_setting('LATEST_POSTS'),
help_text=_('The number of latests '
2015-09-12 22:33:13 +00:00
u'articles to be displayed.'))
2015-09-12 22:46:05 +00:00
tags = TaggableManager(_('filter by tag'), blank=True,
help_text=_('Show only the blog articles tagged with chosen tags.'),
related_name='djangocms_blog_latest_post')
2015-09-12 22:33:13 +00:00
categories = models.ManyToManyField('djangocms_blog.BlogCategory', blank=True,
2015-09-12 22:46:05 +00:00
verbose_name=_('filter by category'),
help_text=_('Show only the blog articles tagged '
2015-09-12 22:33:13 +00:00
u'with chosen categories.'))
2014-01-04 16:07:09 +00:00
2014-10-16 15:40:25 +00:00
def __str__(self):
2015-09-12 22:46:05 +00:00
return _('%s latest articles by tag') % self.latest_posts
2014-01-04 16:07:09 +00:00
def copy_relations(self, oldinstance):
for tag in oldinstance.tags.all():
self.tags.add(tag)
2014-01-04 16:07:09 +00:00
def get_posts(self, request):
posts = self.post_queryset(request)
2015-04-20 00:42:34 +00:00
if self.tags.exists():
posts = posts.filter(tags__in=list(self.tags.all()))
if self.categories.exists():
posts = posts.filter(categories__in=list(self.categories.all()))
return posts.distinct()[:self.latest_posts]
2014-01-04 16:07:09 +00:00
class AuthorEntriesPlugin(BasePostPlugin):
2014-09-04 07:16:56 +00:00
authors = models.ManyToManyField(
2015-07-18 21:06:47 +00:00
dj_settings.AUTH_USER_MODEL, verbose_name=_('authors'),
2014-09-04 07:16:56 +00:00
limit_choices_to={'djangocms_blog_post_author__publish': True}
)
latest_posts = models.IntegerField(
2015-09-12 22:46:05 +00:00
_('articles'), default=get_setting('LATEST_POSTS'),
help_text=_('The number of author articles to be displayed.')
2014-09-04 07:16:56 +00:00
)
2014-01-04 16:07:09 +00:00
2014-10-16 15:40:25 +00:00
def __str__(self):
2015-09-12 22:46:05 +00:00
return _('%s latest articles by author') % self.latest_posts
2014-01-04 16:07:09 +00:00
def copy_relations(self, oldinstance):
self.authors = oldinstance.authors.all()
def get_posts(self, request):
posts = self.post_queryset(request)
2014-01-04 16:07:09 +00:00
return posts[:self.latest_posts]
def get_authors(self):
authors = self.authors.all()
for author in authors:
2014-06-09 21:29:34 +00:00
author.count = 0
2015-09-19 23:11:14 +00:00
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
2014-01-04 16:07:09 +00:00
return authors
2015-09-19 23:11:14 +00:00
class GenericBlogPlugin(BasePostPlugin):
class Meta:
abstract = False