"""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 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 with_base_related(self): """Return qs with related objects.""" return self.select_related('news_type', 'country').prefetch_related('tags') def with_extended_related(self): """Return qs with related objects.""" return self.select_related('created_by') def by_type(self, news_type): """Filter News by type""" return self.filter(news_type__name=news_type) def by_tags(self, tags): return self.filter(tags__in=tags) 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) # todo: filter by best score # todo: filter by country? def should_read(self, news): return self.model.objects.exclude(pk=news.pk).published().\ with_base_related().by_type(news.news_type).distinct().order_by('?') def same_theme(self, news): return self.model.objects.exclude(pk=news.pk).published().\ with_base_related().by_type(news.news_type).\ by_tags(news.tags.all()).distinct().order_by('-start') 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')) state = models.PositiveSmallIntegerField(default=WAITING, choices=STATE_CHOICES, verbose_name=_('State')) 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 should_read(self): return self.__class__.objects.should_read(self)[:3] @property def same_theme(self): return self.__class__.objects.same_theme(self)[:3]