gm-148: refactored news serializer
This commit is contained in:
parent
f1eec96ce8
commit
14ae75f088
|
|
@ -149,7 +149,7 @@ class EstablishmentQuerySet(models.QuerySet):
|
||||||
.filter(image_url__isnull=False, public_mark__gte=10)
|
.filter(image_url__isnull=False, public_mark__gte=10)
|
||||||
.has_published_reviews()
|
.has_published_reviews()
|
||||||
.annotate_distance(point=establishment.location)
|
.annotate_distance(point=establishment.location)
|
||||||
.order_by('distance')[:settings.LIMITING_QUERY_NUMBER]
|
.order_by('distance')[:settings.LIMITING_QUERY_OBJECTS]
|
||||||
.values('id')
|
.values('id')
|
||||||
)
|
)
|
||||||
return self.filter(id__in=subquery_filter_by_distance) \
|
return self.filter(id__in=subquery_filter_by_distance) \
|
||||||
|
|
@ -168,7 +168,7 @@ class EstablishmentQuerySet(models.QuerySet):
|
||||||
self.filter(image_url__isnull=False, public_mark__gte=10)
|
self.filter(image_url__isnull=False, public_mark__gte=10)
|
||||||
.has_published_reviews()
|
.has_published_reviews()
|
||||||
.annotate_distance(point=point)
|
.annotate_distance(point=point)
|
||||||
.order_by('distance')[:settings.LIMITING_QUERY_NUMBER]
|
.order_by('distance')[:settings.LIMITING_QUERY_OBJECTS]
|
||||||
.values('id')
|
.values('id')
|
||||||
)
|
)
|
||||||
return self.filter(id__in=subquery_filter_by_distance) \
|
return self.filter(id__in=subquery_filter_by_distance) \
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
"""News app models."""
|
"""News app models."""
|
||||||
from django.db import models
|
|
||||||
from django.contrib.contenttypes import fields as generic
|
from django.contrib.contenttypes import fields as generic
|
||||||
|
from django.db import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
from rest_framework.reverse import reverse
|
from rest_framework.reverse import reverse
|
||||||
|
|
||||||
from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin
|
from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -64,7 +65,7 @@ class News(BaseAttributes, TranslatedFieldsMixin):
|
||||||
end = models.DateTimeField(blank=True, null=True, default=None,
|
end = models.DateTimeField(blank=True, null=True, default=None,
|
||||||
verbose_name=_('End'))
|
verbose_name=_('End'))
|
||||||
slug = models.SlugField(unique=True, max_length=50, null=True,
|
slug = models.SlugField(unique=True, max_length=50, null=True,
|
||||||
verbose_name=_('News slug'), editable=True,)
|
verbose_name=_('News slug'), editable=True,)
|
||||||
playlist = models.IntegerField(_('playlist'))
|
playlist = models.IntegerField(_('playlist'))
|
||||||
is_publish = models.BooleanField(default=False,
|
is_publish = models.BooleanField(default=False,
|
||||||
verbose_name=_('Publish status'))
|
verbose_name=_('Publish status'))
|
||||||
|
|
@ -74,10 +75,14 @@ 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,
|
# image_url = models.URLField(blank=True, null=True, default=None,
|
||||||
verbose_name=_('Image URL path'))
|
# verbose_name=_('Image URL path'))
|
||||||
preview_image_url = models.URLField(blank=True, null=True, default=None,
|
# preview_image_url = models.URLField(blank=True, null=True, default=None,
|
||||||
verbose_name=_('Preview image URL path'))
|
# 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)
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,81 @@
|
||||||
"""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."""
|
||||||
|
|
||||||
|
|
@ -20,6 +89,8 @@ 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()
|
||||||
|
|
@ -39,13 +110,16 @@ class NewsBaseSerializer(serializers.ModelSerializer):
|
||||||
'title_translated',
|
'title_translated',
|
||||||
'subtitle_translated',
|
'subtitle_translated',
|
||||||
'is_highlighted',
|
'is_highlighted',
|
||||||
'image_url',
|
|
||||||
'preview_image_url',
|
|
||||||
'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."""
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,12 @@ import random
|
||||||
import re
|
import re
|
||||||
import string
|
import string
|
||||||
|
|
||||||
|
import requests
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.http.request import HttpRequest
|
from django.http.request import HttpRequest
|
||||||
from django.utils.timezone import datetime
|
from django.utils.timezone import datetime
|
||||||
|
from rest_framework import status
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -86,3 +88,12 @@ def get_contenttype(app_label: str, model: str):
|
||||||
qs = ContentType.objects.filter(app_label=app_label, model=model)
|
qs = ContentType.objects.filter(app_label=app_label, model=model)
|
||||||
if qs.exists():
|
if qs.exists():
|
||||||
return qs.first()
|
return qs.first()
|
||||||
|
|
||||||
|
|
||||||
|
def image_url_valid(url: str):
|
||||||
|
# In case if image storage is not on CDN
|
||||||
|
if not url.startswith('http') and url.startswith('/media/'):
|
||||||
|
url = f'{settings.SCHEMA_URI}://{settings.DOMAIN_URI}{url}'
|
||||||
|
response = requests.request('head', url)
|
||||||
|
if response.status_code == status.HTTP_200_OK:
|
||||||
|
return True
|
||||||
|
|
|
||||||
|
|
@ -52,4 +52,4 @@ class EstablishmentPortionPagination(ProjectMobilePagination):
|
||||||
"""
|
"""
|
||||||
Pagination for app establishments with limit page size equal to 12
|
Pagination for app establishments with limit page size equal to 12
|
||||||
"""
|
"""
|
||||||
page_size = settings.LIMITING_OUTPUT_OBJECTS
|
page_size = settings.QUERY_OUTPUT_OBJECTS
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,7 @@ CELERY_TASK_SERIALIZER = 'json'
|
||||||
CELERY_RESULT_SERIALIZER = 'json'
|
CELERY_RESULT_SERIALIZER = 'json'
|
||||||
CELERY_TIMEZONE = TIME_ZONE
|
CELERY_TIMEZONE = TIME_ZONE
|
||||||
|
|
||||||
# Django FCM (Firebase push notificatoins)
|
# Django FCM (Firebase push notifications)
|
||||||
FCM_DJANGO_SETTINGS = {
|
FCM_DJANGO_SETTINGS = {
|
||||||
'FCM_SERVER_KEY': (
|
'FCM_SERVER_KEY': (
|
||||||
"AAAAJcC4Vbc:APA91bGovq7233-RHu2MbZTsuMU4jNf3obOue8s"
|
"AAAAJcC4Vbc:APA91bGovq7233-RHu2MbZTsuMU4jNf3obOue8s"
|
||||||
|
|
@ -327,30 +327,18 @@ FCM_DJANGO_SETTINGS = {
|
||||||
|
|
||||||
# Thumbnail settings
|
# Thumbnail settings
|
||||||
THUMBNAIL_ALIASES = {
|
THUMBNAIL_ALIASES = {
|
||||||
'news_preview': {
|
'': {
|
||||||
'web': {'size': (300, 260), }
|
'news_preview_web': {'size': (300, 260), },
|
||||||
},
|
'news_promo_horizontal_web': {'size': (1900, 600), },
|
||||||
'news_promo_horizontal': {
|
'news_promo_horizontal_mobile': {'size': (375, 260), },
|
||||||
'web': {'size': (1900, 600), },
|
'news_tile_horizontal_web': {'size': (300, 275), },
|
||||||
'mobile': {'size': (375, 260), },
|
'news_tile_horizontal_mobile': {'size': (343, 180), },
|
||||||
},
|
'news_tile_vertical_web': {'size': (300, 380), },
|
||||||
'news_tile_horizontal': {
|
'news_highlight_vertical': {'size': (460, 630), },
|
||||||
'web': {'size': (300, 275), },
|
'news_editor_web': {'size': (940, 430), }, # при загрузке через контент эдитор
|
||||||
'mobile': {'size': (343, 180), },
|
'news_editor_mobile': {'size': (343, 260), }, # через контент эдитор в мобильном браузерe
|
||||||
},
|
'avatar_comments_web': {'size': (116, 116), },
|
||||||
'news_tile_vertical': {
|
}
|
||||||
'web': {'size': (300, 380), },
|
|
||||||
},
|
|
||||||
'news_highlight_vertical': {
|
|
||||||
'web': {'size': (460, 630), },
|
|
||||||
},
|
|
||||||
'news_editor': {
|
|
||||||
'web': {'size': (940, 430), }, # при загрузке через контент эдитор
|
|
||||||
'mobile': {'size': (343, 260), }, # через контент эдитор в мобильном браузерe
|
|
||||||
},
|
|
||||||
'avatar_comments': {
|
|
||||||
'web': {'size': (116, 116), },
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Password reset
|
# Password reset
|
||||||
|
|
@ -431,9 +419,9 @@ SITE_NAME = 'Gault & Millau'
|
||||||
# Used in annotations for establishments.
|
# Used in annotations for establishments.
|
||||||
DEFAULT_ESTABLISHMENT_PUBLIC_MARK = 10
|
DEFAULT_ESTABLISHMENT_PUBLIC_MARK = 10
|
||||||
# Limit output objects (see in pagination classes).
|
# Limit output objects (see in pagination classes).
|
||||||
LIMITING_OUTPUT_OBJECTS = 12
|
QUERY_OUTPUT_OBJECTS = 12
|
||||||
# Need to restrict objects to sort (3 times more then expected).
|
# Need to restrict objects to sort (3 times more then expected).
|
||||||
LIMITING_QUERY_NUMBER = LIMITING_OUTPUT_OBJECTS * 3
|
LIMITING_QUERY_OBJECTS = QUERY_OUTPUT_OBJECTS * 3
|
||||||
|
|
||||||
# GEO
|
# GEO
|
||||||
# A Spatial Reference System Identifier
|
# A Spatial Reference System Identifier
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user