154 lines
5.8 KiB
Python
154 lines
5.8 KiB
Python
"""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)),
|
|
is_publish=True, 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."""
|
|
|
|
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, null=True,
|
|
verbose_name=_('News slug'), editable=True,)
|
|
playlist = models.IntegerField(_('playlist'))
|
|
is_publish = models.BooleanField(default=False,
|
|
verbose_name=_('Publish status'))
|
|
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'))
|
|
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 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 on_the_same_theme_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"))\
|
|
.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 you_should_read_news(self):
|
|
|
|
# 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 |