gm-148: in progress
This commit is contained in:
parent
14ae75f088
commit
7f79ce8945
|
|
@ -1,15 +1,38 @@
|
||||||
|
from django.db import models
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from easy_thumbnails.fields import ThumbnailerImageField
|
from easy_thumbnails.fields import ThumbnailerImageField
|
||||||
|
|
||||||
from utils.methods import image_path
|
from utils.methods import image_path
|
||||||
from utils.models import ProjectBaseMixin, ImageMixin
|
from utils.models import ProjectBaseMixin, ImageMixin, PlatformMixin
|
||||||
|
|
||||||
|
|
||||||
class Image(ProjectBaseMixin, ImageMixin):
|
class ImageQuerySet(models.QuerySet):
|
||||||
|
"""QuerySet for model Image."""
|
||||||
|
|
||||||
|
|
||||||
|
class Image(ProjectBaseMixin, ImageMixin, PlatformMixin):
|
||||||
"""Image model."""
|
"""Image model."""
|
||||||
|
HORIZONTAL = 0
|
||||||
|
VERTICAL = 1
|
||||||
|
|
||||||
|
ORIENTATIONS = (
|
||||||
|
(HORIZONTAL, _('Horizontal')),
|
||||||
|
(VERTICAL, _('Vertical')),
|
||||||
|
)
|
||||||
|
|
||||||
image = ThumbnailerImageField(upload_to=image_path,
|
image = ThumbnailerImageField(upload_to=image_path,
|
||||||
verbose_name=_('Image file'))
|
verbose_name=_('image file'))
|
||||||
|
parent = models.ForeignKey('self',
|
||||||
|
blank=True, null=True, default=None,
|
||||||
|
related_name='parent_image',
|
||||||
|
on_delete=models.SET_DEFAULT,
|
||||||
|
verbose_name=_('parent image'))
|
||||||
|
orientation = models.PositiveSmallIntegerField(choices=ORIENTATIONS,
|
||||||
|
blank=True, null=True, default=None,
|
||||||
|
verbose_name=_('image orientation'))
|
||||||
|
title = models.CharField(_('title'), max_length=255, default='')
|
||||||
|
|
||||||
|
objects = ImageQuerySet.as_manager()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,13 @@ class ImageSerializer(serializers.ModelSerializer):
|
||||||
# REQUEST
|
# REQUEST
|
||||||
file = serializers.ImageField(source='image',
|
file = serializers.ImageField(source='image',
|
||||||
write_only=True)
|
write_only=True)
|
||||||
|
title = serializers.CharField()
|
||||||
|
|
||||||
# RESPONSE
|
# RESPONSE
|
||||||
url = serializers.ImageField(source='image',
|
url = serializers.ImageField(source='image',
|
||||||
read_only=True)
|
read_only=True)
|
||||||
|
orientation_display = serializers.CharField(source='get_orientation_display',
|
||||||
|
read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class"""
|
"""Meta class"""
|
||||||
|
|
@ -19,6 +22,10 @@ class ImageSerializer(serializers.ModelSerializer):
|
||||||
fields = (
|
fields = (
|
||||||
'id',
|
'id',
|
||||||
'file',
|
'file',
|
||||||
'url'
|
'url',
|
||||||
|
'parent',
|
||||||
|
'orientation',
|
||||||
|
'orientation_display',
|
||||||
|
'title',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -75,14 +75,6 @@ class News(BaseAttributes, TranslatedFieldsMixin):
|
||||||
verbose_name=_('Is highlighted'))
|
verbose_name=_('Is highlighted'))
|
||||||
# TODO: metadata_keys - описание ключей для динамического построения полей метаданных
|
# TODO: metadata_keys - описание ключей для динамического построения полей метаданных
|
||||||
# TODO: metadata_values - Описание значений для динамических полей из MetadataKeys
|
# 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'))
|
|
||||||
image = models.ForeignKey('gallery.Image',
|
|
||||||
blank=True, null=True,
|
|
||||||
default=None, verbose_name=_('Image'),
|
|
||||||
on_delete=models.SET_NULL)
|
|
||||||
address = models.ForeignKey('location.Address', blank=True, null=True,
|
address = models.ForeignKey('location.Address', blank=True, null=True,
|
||||||
default=None, verbose_name=_('address'),
|
default=None, verbose_name=_('address'),
|
||||||
on_delete=models.SET_NULL)
|
on_delete=models.SET_NULL)
|
||||||
|
|
@ -105,3 +97,34 @@ class News(BaseAttributes, TranslatedFieldsMixin):
|
||||||
@property
|
@property
|
||||||
def web_url(self):
|
def web_url(self):
|
||||||
return reverse('web:news:rud', kwargs={'slug': self.slug})
|
return reverse('web:news:rud', kwargs={'slug': self.slug})
|
||||||
|
|
||||||
|
|
||||||
|
class NewsGalleryQuerySet(models.QuerySet):
|
||||||
|
"""QuerySet for model News"""
|
||||||
|
|
||||||
|
def originals(self):
|
||||||
|
"""Return QuerySet with originals images."""
|
||||||
|
return self.filter(gallery__parent__isnull=True)
|
||||||
|
|
||||||
|
def crops(self):
|
||||||
|
"""Return QuerySet with cropped images."""
|
||||||
|
return self.filter(gallery__parent__isnull=False)
|
||||||
|
|
||||||
|
|
||||||
|
class NewsGallery(models.Model):
|
||||||
|
|
||||||
|
news = models.ForeignKey(News, null=True,
|
||||||
|
related_name='news_gallery',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
verbose_name=_('news'))
|
||||||
|
gallery = models.ForeignKey('gallery.Image', null=True,
|
||||||
|
related_name='news_gallery',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
verbose_name=_('gallery'))
|
||||||
|
|
||||||
|
objects = NewsGalleryQuerySet.as_manager()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
"""NewsGallery meta class."""
|
||||||
|
verbose_name = _('news gallery')
|
||||||
|
verbose_name_plural = _('news galleries')
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,13 @@
|
||||||
"""News app common serializers."""
|
"""News app common serializers."""
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from gallery.models import Image
|
|
||||||
from location import models as location_models
|
from location import models as location_models
|
||||||
from location.serializers import CountrySimpleSerializer
|
from location.serializers import CountrySimpleSerializer
|
||||||
from main.serializers import MetaDataContentSerializer
|
from main.serializers import MetaDataContentSerializer
|
||||||
from news import models
|
from news import models
|
||||||
from utils.methods import image_url_valid
|
|
||||||
from utils.serializers import TranslatedField
|
from utils.serializers import TranslatedField
|
||||||
|
|
||||||
|
|
||||||
class NewsPromoImageSerializer(serializers.Serializer):
|
|
||||||
|
|
||||||
horizontal_web_image = serializers.SerializerMethodField()
|
|
||||||
horizontal_mobile_image = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
def get_horizontal_web_image(self, obj):
|
|
||||||
return obj['news_promo_horizontal_web'].url
|
|
||||||
|
|
||||||
def get_horizontal_mobile_image(self, obj):
|
|
||||||
return obj['news_promo_horizontal_mobile'].url
|
|
||||||
|
|
||||||
|
|
||||||
class NewsTileImageSerializer(serializers.Serializer):
|
|
||||||
|
|
||||||
horizontal_web_image = serializers.SerializerMethodField()
|
|
||||||
horizontal_mobile_image = serializers.SerializerMethodField()
|
|
||||||
vertical_web_image = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
def get_horizontal_web_image(self, obj):
|
|
||||||
return obj['news_tile_horizontal_web'].url
|
|
||||||
|
|
||||||
def get_horizontal_mobile_image(self, obj):
|
|
||||||
return obj['news_tile_horizontal_mobile'].url
|
|
||||||
|
|
||||||
def get_vertical_web_image(self, obj):
|
|
||||||
return obj['news_tile_vertical_web'].url
|
|
||||||
|
|
||||||
|
|
||||||
class NewsHighlightImageSerializer(serializers.Serializer):
|
|
||||||
|
|
||||||
vertical_web_image = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
def get_vertical_web_image(self, obj):
|
|
||||||
return obj['news_highlight_vertical'].url
|
|
||||||
|
|
||||||
|
|
||||||
class NewsEditorImageSerializer(serializers.Serializer):
|
|
||||||
|
|
||||||
web_image = serializers.SerializerMethodField()
|
|
||||||
mobile_image = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
def get_web_image(self, obj):
|
|
||||||
return obj['news_editor_web'].url
|
|
||||||
|
|
||||||
def get_mobile_image(self, obj):
|
|
||||||
return obj['news_editor_mobile'].url
|
|
||||||
|
|
||||||
|
|
||||||
class NewsGallerySerializer(serializers.ModelSerializer):
|
|
||||||
|
|
||||||
promo_images = NewsPromoImageSerializer(source='image')
|
|
||||||
tile_images = NewsTileImageSerializer(source='image')
|
|
||||||
highlight_images = NewsHighlightImageSerializer(source='image')
|
|
||||||
editor_images = NewsEditorImageSerializer(source='image')
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
"""Meta class."""
|
|
||||||
model = Image
|
|
||||||
fields = [
|
|
||||||
'promo_images',
|
|
||||||
'tile_images',
|
|
||||||
'highlight_images',
|
|
||||||
'editor_images',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class NewsTypeSerializer(serializers.ModelSerializer):
|
class NewsTypeSerializer(serializers.ModelSerializer):
|
||||||
"""News type serializer."""
|
"""News type serializer."""
|
||||||
|
|
||||||
|
|
@ -89,8 +21,6 @@ class NewsTypeSerializer(serializers.ModelSerializer):
|
||||||
class NewsBaseSerializer(serializers.ModelSerializer):
|
class NewsBaseSerializer(serializers.ModelSerializer):
|
||||||
"""Base serializer for News model."""
|
"""Base serializer for News model."""
|
||||||
|
|
||||||
gallery = serializers.SerializerMethodField()
|
|
||||||
|
|
||||||
# read only fields
|
# read only fields
|
||||||
title_translated = TranslatedField()
|
title_translated = TranslatedField()
|
||||||
subtitle_translated = TranslatedField()
|
subtitle_translated = TranslatedField()
|
||||||
|
|
@ -113,13 +43,8 @@ class NewsBaseSerializer(serializers.ModelSerializer):
|
||||||
'news_type',
|
'news_type',
|
||||||
'tags',
|
'tags',
|
||||||
'slug',
|
'slug',
|
||||||
'gallery',
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_gallery(self, obj):
|
|
||||||
if image_url_valid(url=obj.image.image.url):
|
|
||||||
return NewsGallerySerializer(obj.image).data
|
|
||||||
|
|
||||||
|
|
||||||
class NewsDetailSerializer(NewsBaseSerializer):
|
class NewsDetailSerializer(NewsBaseSerializer):
|
||||||
"""News detail serializer."""
|
"""News detail serializer."""
|
||||||
|
|
|
||||||
|
|
@ -92,8 +92,20 @@ def get_contenttype(app_label: str, model: str):
|
||||||
|
|
||||||
def image_url_valid(url: str):
|
def image_url_valid(url: str):
|
||||||
# In case if image storage is not on CDN
|
# In case if image storage is not on CDN
|
||||||
if not url.startswith('http') and url.startswith('/media/'):
|
if url.startswith('/media/'):
|
||||||
url = f'{settings.SCHEMA_URI}://{settings.DOMAIN_URI}{url}'
|
url = f'{settings.SCHEMA_URI}://{settings.DOMAIN_URI}{url}'
|
||||||
response = requests.request('head', url)
|
response = requests.request('head', url)
|
||||||
if response.status_code == status.HTTP_200_OK:
|
if response.status_code == status.HTTP_200_OK:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def absolute_url_decorator(func):
|
||||||
|
def get_absolute_image_url(self, obj):
|
||||||
|
"""Get absolute image url"""
|
||||||
|
url_path = func(self, obj)
|
||||||
|
if url_path:
|
||||||
|
if url_path.startswith('/media/'):
|
||||||
|
return f'{settings.SCHEMA_URI}://{settings.DOMAIN_URI}{url_path}/'
|
||||||
|
else:
|
||||||
|
return url_path
|
||||||
|
return get_absolute_image_url
|
||||||
|
|
|
||||||
|
|
@ -328,19 +328,23 @@ FCM_DJANGO_SETTINGS = {
|
||||||
# Thumbnail settings
|
# Thumbnail settings
|
||||||
THUMBNAIL_ALIASES = {
|
THUMBNAIL_ALIASES = {
|
||||||
'': {
|
'': {
|
||||||
'news_preview_web': {'size': (300, 260), },
|
'news_preview': {'size': (300, 260), },
|
||||||
'news_promo_horizontal_web': {'size': (1900, 600), },
|
'news_promo_horizontal_web': {'size': (1900, 600), },
|
||||||
'news_promo_horizontal_mobile': {'size': (375, 260), },
|
'news_promo_horizontal_mobile': {'size': (375, 260), },
|
||||||
'news_tile_horizontal_web': {'size': (300, 275), },
|
'news_tile_horizontal_web': {'size': (300, 275), },
|
||||||
'news_tile_horizontal_mobile': {'size': (343, 180), },
|
'news_tile_horizontal_mobile': {'size': (343, 180), },
|
||||||
'news_tile_vertical_web': {'size': (300, 380), },
|
'news_tile_vertical_web': {'size': (300, 380), },
|
||||||
'news_highlight_vertical': {'size': (460, 630), },
|
'news_highlight_vertical_web': {'size': (460, 630), },
|
||||||
'news_editor_web': {'size': (940, 430), }, # при загрузке через контент эдитор
|
'news_editor_web': {'size': (940, 430), }, # при загрузке через контент эдитор
|
||||||
'news_editor_mobile': {'size': (343, 260), }, # через контент эдитор в мобильном браузерe
|
'news_editor_mobile': {'size': (343, 260), }, # через контент эдитор в мобильном браузерe
|
||||||
'avatar_comments_web': {'size': (116, 116), },
|
'avatar_comments_web': {'size': (116, 116), },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
THUMBNAIL_DEFAULT_OPTIONS = {
|
||||||
|
'crop': 'smart',
|
||||||
|
}
|
||||||
|
|
||||||
# Password reset
|
# Password reset
|
||||||
RESETTING_TOKEN_EXPIRATION = 24 # hours
|
RESETTING_TOKEN_EXPIRATION = 24 # hours
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user