# -*- coding: utf-8 -*- from itertools import chain from django.db import models from django.contrib.contenttypes import generic from django.utils.translation import ugettext_lazy as _ from django.utils.timezone import now from django.db.models.signals import post_save from hvad.models import TranslatableModel, TranslatedFields, TranslationManager from sorl.thumbnail import ImageField from functions.signal_handlers import post_save_handler from functions.url_utils import slugify, unique_slug from functions.model_utils import base_concrete_model from functions.form_check import translit_with_separator from article.managers import ArticleManager class Author(models.Model): class Meta: verbose_name = _(u'Автор') verbose_name_plural = _(u'Авторы') photo = models.ImageField(_(u'Фото'), upload_to='authors', blank=True, null=True) fullname = models.CharField(_(u'Полное имя автора'), max_length=255) position = models.CharField(_(u'Должность'), max_length=255, null=True, blank=True) email = models.EmailField(_(u'Емейл'), null=True, blank=True) fb = models.URLField(_(u'Facebook'), null=True, blank=True) vk = models.URLField(_(u'Vk'), null=True, blank=True) linkedin = models.URLField(_(u'LinkedIn'), null=True, blank=True) instagram = models.URLField(_(u'Instagram'), null=True, blank=True) about = models.TextField(_(u'Об авторе'), blank=True) def __unicode__(self): return unicode(self.fullname) class Article(TranslatableModel): """ Create Article model Uses hvad.TranslatableModel which is child of django.db.models class """ MAX_ON_MAIN_PAGE = 3 # types of article blog = 1 news = 2 objects = ArticleManager() slug = models.SlugField(verbose_name=_(u'Url'), unique=True, max_length=255) # fields provides importing and reindexing new articles from previous site old_id = models.IntegerField(verbose_name=_(u'Id из старой базы'), blank=True, null=True) logo = ImageField(verbose_name=_(u'Логотип'), upload_to='articles_preview', blank=True) theme = models.ManyToManyField('theme.Theme', verbose_name=_(u'Тематики')) tag = models.ManyToManyField('theme.Tag', blank=True, null=True, verbose_name=_(u'Теги'), ) author = models.ForeignKey('accounts.User', verbose_name=_(u'Автор'), on_delete=models.PROTECT, related_name='articles') author_s = models.ForeignKey(Author, verbose_name=_(u'Автор'), on_delete=models.PROTECT, related_name='articles', null=True, blank=True) exposition = models.ForeignKey('exposition.Exposition', blank=True, null=True, verbose_name=_(u'Выставка')) conference = models.ForeignKey('conference.Conference', blank=True, null=True, verbose_name=_(u'Конференция')) # type can be blog or news type = models.PositiveSmallIntegerField(verbose_name=_(u'Тип'), default=1, db_index=True) # do not use anywhere now allow_comments = models.BooleanField(verbose_name=_(u'Позволить коментарии'), default=True) # fields that provides features of a visible page on the website publish_date = models.DateTimeField(verbose_name=_(u'Дата публикации'), blank=True, null=True, db_index=True) expiry_date = models.DateTimeField(_("Expires on"), help_text=_("With Published chosen, won't be shown after this time"), blank=True, null=True) in_sitemap = models.BooleanField(_("Show in sitemap"), default=False) # fields that provides features of a visible on main page main_page = models.BooleanField(verbose_name=_(u'Показывать на главной'), default=False, db_index=True) main_page_time = models.DateTimeField(blank=True, null=True) # field that check if need generate description gen_description = models.BooleanField(_("Generate description"), help_text=_("If checked, the description will be automatically " "generated from content. Uncheck if you want to manually " "set a custom description."), default=False) created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) draft = models.BooleanField(_(u'Черновик'), default=False, blank=True, db_index=True) #translated fields translations = TranslatedFields( main_title=models.CharField(verbose_name=_(u'Заголовок'), max_length=255), preview=models.TextField(verbose_name=_(u'Превью'), ), description=models.TextField(verbose_name=_(u'Основной текст'), blank=False), short_description=models.TextField(_(u'Краткое содержание'), blank=True), #-----meta title=models.CharField(max_length=255, blank=True), descriptions=models.CharField(max_length=255, blank=True), keywords=models.CharField(max_length=255, blank=True), ) files = generic.GenericRelation('file.FileModel', content_type_field='content_type', object_id_field='object_id') comments = generic.GenericRelation('comments.Comment') class Meta: ordering = ['-publish_date'] def __unicode__(self): return self.lazy_translation_getter('main_title', self.pk) def translation_model(self): return self._meta.translations_model def publish(self): """ set publish date. uses when publish date is none """ self.in_sitemap = True if not self.publish_date: # save time only first time self.publish_date = now() self.save() return self def get_event(self): """ get event connected to article exposition has priority """ if self.exposition: return self.exposition elif self.conference: return self.conference return None def save(self, *args, **kwargs): # If no slug is provided, generates one before saving. if not self.slug: self.slug = self.generate_unique_slug() # Set the description field on save. # if self.gen_description: # self.description = strip_tags(self.description_from_content()) super(Article, self).save(*args, **kwargs) def description_from_content(self): """ """ # place for logic return '' def generate_unique_slug(self): """ Create a unique slug by passing the result of get_slug() to utils.urls.unique_slug, which appends an index if necessary. """ # For custom content types, use the ``Page`` instance for # slug lookup. concrete_model = base_concrete_model(Article, self) slug_qs = concrete_model.objects.exclude(id=self.id) slug = unique_slug(slug_qs, "slug", self.get_slug()) slug = translit_with_separator(slug) return slug def get_slug(self): """ Allows subclasses to implement their own slug creation logic. """ return slugify(self.get_available_title()) def get_available_title(self): """ get title from current language """ return u'%s' % self.lazy_translation_getter('main_title', self.pk) def _get_next_or_previous_by_publish_date(self, is_next, **kwargs): """ Retrieves next or previous object by publish date. We implement our own version instead of Django's so we can hook into the published manager and concrete subclasses. """ arg = "publish_date__gt" if is_next else "publish_date__lt" order = "publish_date" if is_next else "-publish_date" lookup = {arg: self.publish_date} concrete_model = base_concrete_model(Article, self) try: queryset = concrete_model.objects.published except AttributeError: queryset = concrete_model.objects.all try: return queryset(**kwargs).filter(**lookup).order_by(order)[0] except IndexError: pass def get_next_by_publish_date(self, **kwargs): """ Retrieves next object by publish date. """ return self._get_next_or_previous_by_publish_date(True, **kwargs) def get_previous_by_publish_date(self, **kwargs): """ Retrieves previous object by publish date. """ return self._get_next_or_previous_by_publish_date(False, **kwargs) def admin_url(self): """ returns url for admin pages """ if self.type == 1: return '/admin/article/blog/%s' % self.slug elif self.type == 2: return '/admin/article/news/%s' % self.slug def get_permanent_url(self): """ returns object url on site(get_absolute_url analog) """ if self.type == 1: return '/blogs/%s/' % self.slug elif self.type == 2: return '/news/%s/' % self.slug def get_blog_preview(self): """ returns preview(fildemodel) if it exist gor current object """ preview = self.files.filter(purpose='preview') if preview: return preview[0] else: return None def get_blog_preview2(self): preview = self.files.filter(purpose='preview2') if preview: return preview[0] else: return None def get_catalog(self): """ get catalog for current objects catalogs different for news and blogs """ if self.type == 1: return '/blogs/' elif self.type == 2: return '/news/' def similar(self): """ returns list of articles with same type and themes :return: """ themes = [item['id'] for item in self.theme.all().values('id')] return list(Article.objects.language() .exclude(id=self.id) .filter(type=self.type, publish_date__isnull=False, theme__in=themes) .distinct() .order_by('-publish_date')[:3]) def get_similar(self): if getattr(self, '_similar', None) is None: model = self.__class__ result = [] tags = self.tag.all().values_list('pk', flat=True) themes = self.theme.all().values_list('pk', flat=True) exclude_pks = set([self.pk]) qs = model.objects.language()\ .filter(type=self.type, publish_date__isnull=False).distinct().order_by('-publish_date') tags_sim = qs.filter(tag__in=tags).exclude(pk__in=exclude_pks)[:4] exclude_pks.update([x.pk for x in tags_sim]) themes_sim = qs.filter(theme__in=themes).exclude(pk__in=exclude_pks)[:4] exclude_pks.update([x.pk for x in themes_sim]) last_sim = qs.exclude(pk__in=exclude_pks)[:4] result = list(chain(tags_sim, themes_sim, last_sim))[:4] self._similar = result return self._similar post_save.connect(post_save_handler, sender=Article)