"""News app models.""" from django.db import models from django.contrib.contenttypes import fields as generic from django.utils import timezone from django.utils.translation import gettext_lazy as _ from rest_framework.reverse import reverse from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin from random import sample as random_sample class NewsType(models.Model): """NewsType model.""" name = models.CharField(_('name'), max_length=250) class Meta: """Meta class.""" verbose_name_plural = _('news types') verbose_name = _('news type') def __str__(self): """Overrided __str__ method.""" return self.name class NewsQuerySet(models.QuerySet): """QuerySet for model News""" def by_type(self, news_type): """Filter News by type""" return self.filter(news_type__name=news_type) def by_country_code(self, code): """Filter collection by country code.""" return self.filter(country__code=code) def published(self): """Return only published news""" now = timezone.now() return self.filter(models.Q(models.Q(end__gte=now) | models.Q(end__isnull=True)), state__in=self.model.PUBLISHED_STATES, start__lte=now) def with_related(self): """Return qs with related objects.""" return self.select_related('news_type', 'country').prefetch_related('tags') class News(BaseAttributes, TranslatedFieldsMixin): """News model.""" STR_FIELD_NAME = 'title' # TEMPLATE CHOICES NEWSPAPER = 0 MAIN_PDF_ERB = 1 MAIN = 2 TEMPLATE_CHOICES = ( (NEWSPAPER, 'newspaper'), (MAIN_PDF_ERB, 'main.pdf.erb'), (MAIN, 'main'), ) # STATE CHOICES WAITING = 0 HIDDEN = 1 PUBLISHED = 2 PUBLISHED_EXCLUSIVE = 3 PUBLISHED_STATES = [PUBLISHED, PUBLISHED_EXCLUSIVE] STATE_CHOICES = ( (WAITING, _('Waiting')), (HIDDEN, _('Hidden')), (PUBLISHED, _('Published')), (PUBLISHED_EXCLUSIVE, _('Published exclusive')), ) news_type = models.ForeignKey(NewsType, on_delete=models.PROTECT, verbose_name=_('news type')) title = TJSONField(blank=True, null=True, default=None, verbose_name=_('title'), help_text='{"en-GB":"some text"}') subtitle = TJSONField(blank=True, null=True, default=None, verbose_name=_('subtitle'), help_text='{"en-GB":"some text"}') description = TJSONField(blank=True, null=True, default=None, verbose_name=_('description'), help_text='{"en-GB":"some text"}') start = models.DateTimeField(verbose_name=_('Start')) end = models.DateTimeField(blank=True, null=True, default=None, verbose_name=_('End')) slug = models.SlugField(unique=True, max_length=50, verbose_name=_('News slug')) playlist = models.IntegerField(_('playlist')) # author = models.CharField(max_length=255, blank=True, null=True, # default=None,verbose_name=_('Author')) state = models.PositiveSmallIntegerField(default=WAITING, choices=STATE_CHOICES, verbose_name=_('State')) author = models.CharField(max_length=255, blank=True, null=True, default=None,verbose_name=_('Author')) is_highlighted = models.BooleanField(default=False, verbose_name=_('Is highlighted')) # TODO: metadata_keys - описание ключей для динамического построения полей метаданных # TODO: metadata_values - Описание значений для динамических полей из MetadataKeys image_url = models.URLField(blank=True, null=True, default=None, verbose_name=_('Image URL path')) preview_image_url = models.URLField(blank=True, null=True, default=None, verbose_name=_('Preview image URL path')) template = models.PositiveIntegerField(choices=TEMPLATE_CHOICES, default=NEWSPAPER) address = models.ForeignKey('location.Address', blank=True, null=True, default=None, verbose_name=_('address'), on_delete=models.SET_NULL) country = models.ForeignKey('location.Country', blank=True, null=True, on_delete=models.SET_NULL, verbose_name=_('country')) tags = generic.GenericRelation(to='main.MetaDataContent') objects = NewsQuerySet.as_manager() class Meta: """Meta class.""" verbose_name = _('news') verbose_name_plural = _('news') def __str__(self): return f'news: {self.slug}' @property def is_publish(self): return self.state in self.PUBLISHED_STATES @property def web_url(self): return reverse('web:news:rud', kwargs={'slug': self.slug}) @property def list_also_like_news(self): # without "distinct" method the doubles are arising like_news = News.objects.published().filter(news_type=self.news_type, tags__in=models.F("tags"))\ .exclude(id=self.id).distinct() news_count = like_news.count() if news_count >= 6: random_ids = random_sample(range(news_count), 6) else: random_ids = random_sample(range(news_count), news_count) news_list = [{"id": like_news[r].id, "slug": like_news[r].slug} for r in random_ids] return news_list @property def same_theme(self): # on the same theme news # without "distinct" method the doubles are arising like_news = News.objects.published().filter(news_type=self.news_type, tags__in=models.F("tags"))\ .order_by("-start").exclude(id=self.id).distinct() news_count = like_news.count() if news_count >= 3: like_news = like_news[:3] news_list = [{"id": n.id, "slug": n.slug} for n in like_news] return news_list @property def should_read(self): # you should read news # without "distinct" method the doubles are arising like_news = News.objects.published().filter(news_type=self.news_type).exclude(id=self.id).distinct() news_count = like_news.count() if news_count >= 3: random_ids = random_sample(range(news_count), 3) else: random_ids = random_sample(range(news_count), news_count) news_list = [{"id": like_news[r].id, "slug": like_news[r].slug} for r in random_ids] return news_list