gm-148: refactored news serializer

This commit is contained in:
Anatoly 2019-09-26 18:38:57 +03:00
parent f1eec96ce8
commit 14ae75f088
6 changed files with 116 additions and 38 deletions

View File

@ -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) \

View File

@ -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)

View File

@ -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."""

View File

@ -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

View File

@ -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

View File

@ -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