Merge branch 'develop' into feature/gm-148

# Conflicts:
#	apps/news/serializers.py
#	project/settings/local.py
This commit is contained in:
Anatoly 2019-10-02 10:20:14 +03:00
commit b31e71d4ef
20 changed files with 165 additions and 153 deletions

View File

@ -1,15 +1,15 @@
import json, pytz import json
import pytz
from datetime import datetime from datetime import datetime
from rest_framework.test import APITestCase
from account.models import User
from rest_framework import status
from http.cookies import SimpleCookie from http.cookies import SimpleCookie
from collection.models import Collection, Guide from rest_framework import status
from location.models import Country from rest_framework.test import APITestCase
from account.models import User
from collection.models import Collection, Guide
from establishment.models import Establishment, EstablishmentType from establishment.models import Establishment, EstablishmentType
# Create your tests here. from location.models import Country
class BaseTestCase(APITestCase): class BaseTestCase(APITestCase):

View File

@ -4,7 +4,7 @@ from rest_framework import permissions
from collection import models from collection import models
from utils.pagination import ProjectPageNumberPagination from utils.pagination import ProjectPageNumberPagination
from django.shortcuts import get_object_or_404 from django.shortcuts import get_object_or_404
from establishment.serializers import EstablishmentListSerializer from establishment.serializers import EstablishmentBaseSerializer
from collection.serializers import common as serializers from collection.serializers import common as serializers
@ -56,7 +56,7 @@ class CollectionEstablishmentListView(CollectionListView):
"""Retrieve list of establishment for collection.""" """Retrieve list of establishment for collection."""
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
pagination_class = ProjectPageNumberPagination pagination_class = ProjectPageNumberPagination
serializer_class = EstablishmentListSerializer serializer_class = EstablishmentBaseSerializer
lookup_field = 'slug' lookup_field = 'slug'
def get_queryset(self): def get_queryset(self):

View File

@ -8,13 +8,13 @@ from django.contrib.gis.geos import Point
from django.contrib.gis.measure import Distance as DistanceMeasure from django.contrib.gis.measure import Distance as DistanceMeasure
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.db.models import When, Case, F, ExpressionWrapper, Subquery from django.db.models import When, Case, F, ExpressionWrapper, Subquery, Q
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 phonenumber_field.modelfields import PhoneNumberField from phonenumber_field.modelfields import PhoneNumberField
from collection.models import Collection from collection.models import Collection
from main.models import MetaDataContent from main.models import Award, MetaDataContent
from location.models import Address from location.models import Address
from review.models import Review from review.models import Review
from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin,
@ -281,7 +281,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
slug = models.SlugField(unique=True, max_length=50, null=True, slug = models.SlugField(unique=True, max_length=50, null=True,
verbose_name=_('Establishment slug'), editable=True) verbose_name=_('Establishment slug'), editable=True)
awards = generic.GenericRelation(to='main.Award') awards = generic.GenericRelation(to='main.Award', related_query_name='establishment')
tags = generic.GenericRelation(to='main.MetaDataContent') tags = generic.GenericRelation(to='main.MetaDataContent')
reviews = generic.GenericRelation(to='review.Review') reviews = generic.GenericRelation(to='review.Review')
comments = generic.GenericRelation(to='comment.Comment') comments = generic.GenericRelation(to='comment.Comment')
@ -330,6 +330,13 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
raise ValidationError('Establishment type of subtype does not match') raise ValidationError('Establishment type of subtype does not match')
self.establishment_subtypes.add(establishment_subtype) self.establishment_subtypes.add(establishment_subtype)
@property
def vintage_year(self):
last_review = self.reviews.by_status(Review.READY).last()
if last_review:
return last_review.vintage
@property @property
def best_price_menu(self): def best_price_menu(self):
return 150 return 150
@ -356,6 +363,11 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
""" """
return self.address.coordinates return self.address.coordinates
@property
def the_most_recent_award(self):
return Award.objects.filter(Q(establishment=self) | Q(employees__establishments=self)).latest(
field_name='vintage_year')
class Position(BaseAttributes, TranslatedFieldsMixin): class Position(BaseAttributes, TranslatedFieldsMixin):
"""Position model.""" """Position model."""
@ -409,8 +421,8 @@ class Employee(BaseAttributes):
verbose_name=_('User')) verbose_name=_('User'))
name = models.CharField(max_length=255, verbose_name=_('Last name')) name = models.CharField(max_length=255, verbose_name=_('Last name'))
establishments = models.ManyToManyField(Establishment, related_name='employees', establishments = models.ManyToManyField(Establishment, related_name='employees',
through=EstablishmentEmployee) through=EstablishmentEmployee,)
awards = generic.GenericRelation(to='main.Award') awards = generic.GenericRelation(to='main.Award', related_query_name='employees')
tags = generic.GenericRelation(to='main.MetaDataContent') tags = generic.GenericRelation(to='main.MetaDataContent')
class Meta: class Meta:

View File

@ -8,7 +8,6 @@ from establishment.serializers import (
from utils.decorators import with_base_attributes from utils.decorators import with_base_attributes
from main.models import Currency from main.models import Currency
from utils.serializers import TJSONSerializer
class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): class EstablishmentListCreateSerializer(EstablishmentBaseSerializer):
@ -89,13 +88,15 @@ class SocialNetworkSerializers(serializers.ModelSerializer):
class PlatesSerializers(PlateSerializer): class PlatesSerializers(PlateSerializer):
"""Social network serializers.""" """Social network serializers."""
name = TJSONSerializer
currency_id = serializers.PrimaryKeyRelatedField( currency_id = serializers.PrimaryKeyRelatedField(
source='currency', source='currency',
queryset=Currency.objects.all(), write_only=True queryset=Currency.objects.all(), write_only=True
) )
class Meta: class Meta:
"""Meta class."""
model = models.Plate model = models.Plate
fields = PlateSerializer.Meta.fields + [ fields = PlateSerializer.Meta.fields + [
'name', 'name',

View File

@ -1,18 +1,17 @@
"""Establishment serializers.""" """Establishment serializers."""
from rest_framework import serializers
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from comment import models as comment_models from comment import models as comment_models
from comment.serializers import common as comment_serializers from comment.serializers import common as comment_serializers
from establishment import models from establishment import models
from favorites.models import Favorites from favorites.models import Favorites
from location.serializers import AddressSimpleSerializer, AddressSerializer from location.serializers import AddressBaseSerializer
from main.models import MetaDataContent from main.models import MetaDataContent
from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer
from review import models as review_models from review import models as review_models
from timetable.serialziers import ScheduleRUDSerializer from timetable.serialziers import ScheduleRUDSerializer
from utils import exceptions as utils_exceptions from utils import exceptions as utils_exceptions
from utils.serializers import TranslatedField from utils.serializers import TranslatedField, ProjectModelSerializer
from utils.serializers import TJSONSerializer
class ContactPhonesSerializer(serializers.ModelSerializer): class ContactPhonesSerializer(serializers.ModelSerializer):
@ -44,9 +43,9 @@ class SocialNetworkRelatedSerializers(serializers.ModelSerializer):
] ]
class PlateSerializer(serializers.ModelSerializer): class PlateSerializer(ProjectModelSerializer):
name_translated = serializers.CharField(allow_null=True, read_only=True) name_translated = TranslatedField()
currency = CurrencySerializer(read_only=True) currency = CurrencySerializer(read_only=True)
class Meta: class Meta:
@ -59,9 +58,8 @@ class PlateSerializer(serializers.ModelSerializer):
] ]
class MenuSerializers(serializers.ModelSerializer): class MenuSerializers(ProjectModelSerializer):
plates = PlateSerializer(read_only=True, many=True, source='plate_set') plates = PlateSerializer(read_only=True, many=True, source='plate_set')
category = TJSONSerializer()
category_translated = serializers.CharField(read_only=True) category_translated = serializers.CharField(read_only=True)
class Meta: class Meta:
@ -75,9 +73,8 @@ class MenuSerializers(serializers.ModelSerializer):
] ]
class MenuRUDSerializers(serializers.ModelSerializer, ): class MenuRUDSerializers(ProjectModelSerializer):
plates = PlateSerializer(read_only=True, many=True, source='plate_set') plates = PlateSerializer(read_only=True, many=True, source='plate_set')
category = TJSONSerializer()
class Meta: class Meta:
model = models.Menu model = models.Menu
@ -141,13 +138,14 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer):
fields = ('id', 'name', 'position_translated', 'awards', 'priority') fields = ('id', 'name', 'position_translated', 'awards', 'priority')
class EstablishmentBaseSerializer(serializers.ModelSerializer): class EstablishmentBaseSerializer(ProjectModelSerializer):
"""Base serializer for Establishment model.""" """Base serializer for Establishment model."""
preview_image = serializers.URLField(source='preview_image_url') preview_image = serializers.URLField(source='preview_image_url')
slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) slug = serializers.SlugField(allow_blank=False, required=True, max_length=50)
address = AddressSerializer() address = AddressBaseSerializer()
tags = MetaDataContentSerializer(many=True) tags = MetaDataContentSerializer(many=True)
in_favorites = serializers.BooleanField(allow_null=True)
class Meta: class Meta:
"""Meta class.""" """Meta class."""
@ -168,27 +166,7 @@ class EstablishmentBaseSerializer(serializers.ModelSerializer):
] ]
class EstablishmentListSerializer(EstablishmentBaseSerializer): class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
"""Serializer for Establishment model."""
in_favorites = serializers.BooleanField(allow_null=True)
class Meta(EstablishmentBaseSerializer.Meta):
"""Meta class."""
fields = EstablishmentBaseSerializer.Meta.fields + [
'in_favorites',
]
class EstablishmentAllListSerializer(EstablishmentListSerializer):
""" Serailizer for api/*/establishments """
address = AddressSimpleSerializer()
class Meta(EstablishmentListSerializer.Meta):
pass
class EstablishmentDetailSerializer(EstablishmentListSerializer):
"""Serializer for Establishment model.""" """Serializer for Establishment model."""
description_translated = TranslatedField() description_translated = TranslatedField()
@ -205,11 +183,12 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer):
menu = MenuSerializers(source='menu_set', many=True, read_only=True) menu = MenuSerializers(source='menu_set', many=True, read_only=True)
best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
vintage_year = serializers.ReadOnlyField()
class Meta(EstablishmentListSerializer.Meta): class Meta(EstablishmentBaseSerializer.Meta):
"""Meta class.""" """Meta class."""
fields = EstablishmentListSerializer.Meta.fields + [ fields = EstablishmentBaseSerializer.Meta.fields + [
'description_translated', 'description_translated',
'image', 'image',
'subtypes', 'subtypes',
@ -229,18 +208,9 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer):
'best_price_menu', 'best_price_menu',
'best_price_carte', 'best_price_carte',
'transportation', 'transportation',
'vintage_year',
] ]
# def get_in_favorites(self, obj):
# """Get in_favorites status flag"""
# user = self.context.get('request').user
# if user.is_authenticated:
# return obj.id in user.favorites.by_content_type(app_label='establishment',
# model='establishment')\
# .values_list('object_id', flat=True)
# else:
# return False
class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer): class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer):
"""Create comment serializer""" """Create comment serializer"""

View File

@ -28,7 +28,7 @@ class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView):
"""Resource for getting a list of establishments.""" """Resource for getting a list of establishments."""
filter_class = filters.EstablishmentFilter filter_class = filters.EstablishmentFilter
serializer_class = serializers.EstablishmentAllListSerializer serializer_class = serializers.EstablishmentBaseSerializer
def get_queryset(self): def get_queryset(self):
"""Overridden method 'get_queryset'.""" """Overridden method 'get_queryset'."""
@ -70,7 +70,8 @@ class EstablishmentRecentReviewListView(EstablishmentListView):
class EstablishmentSimilarListView(EstablishmentListView): class EstablishmentSimilarListView(EstablishmentListView):
"""Resource for getting a list of establishments.""" """Resource for getting a list of establishments."""
serializer_class = serializers.EstablishmentListSerializer
serializer_class = serializers.EstablishmentBaseSerializer
pagination_class = EstablishmentPortionPagination pagination_class = EstablishmentPortionPagination
def get_queryset(self): def get_queryset(self):
@ -96,6 +97,7 @@ class EstablishmentCommentCreateView(generics.CreateAPIView):
class EstablishmentCommentListView(generics.ListAPIView): class EstablishmentCommentListView(generics.ListAPIView):
"""View for return list of establishment comments.""" """View for return list of establishment comments."""
permission_classes = (permissions.AllowAny,) permission_classes = (permissions.AllowAny,)
serializer_class = serializers.EstablishmentCommentCreateSerializer serializer_class = serializers.EstablishmentCommentCreateSerializer
@ -153,11 +155,13 @@ class EstablishmentFavoritesCreateDestroyView(generics.CreateAPIView, generics.D
class EstablishmentNearestRetrieveView(EstablishmentListView, generics.ListAPIView): class EstablishmentNearestRetrieveView(EstablishmentListView, generics.ListAPIView):
"""Resource for getting list of nearest establishments.""" """Resource for getting list of nearest establishments."""
serializer_class = serializers.EstablishmentListSerializer
serializer_class = serializers.EstablishmentBaseSerializer
filter_class = filters.EstablishmentFilter filter_class = filters.EstablishmentFilter
def get_queryset(self): def get_queryset(self):
"""Overridden method 'get_queryset'.""" """Overridden method 'get_queryset'."""
# todo: latitude and longitude
lat = self.request.query_params.get('lat') lat = self.request.query_params.get('lat')
lon = self.request.query_params.get('lon') lon = self.request.query_params.get('lon')
radius = self.request.query_params.get('radius') radius = self.request.query_params.get('radius')

View File

@ -1,13 +1,13 @@
"""Views for app favorites.""" """Views for app favorites."""
from rest_framework import generics from rest_framework import generics
from establishment.models import Establishment from establishment.models import Establishment
from establishment.serializers import EstablishmentListSerializer from establishment.serializers import EstablishmentBaseSerializer
from .models import Favorites from .models import Favorites
class FavoritesBaseView(generics.GenericAPIView): class FavoritesBaseView(generics.GenericAPIView):
"""Base view for Favorites.""" """Base view for Favorites."""
def get_queryset(self): def get_queryset(self):
"""Override get_queryset method.""" """Override get_queryset method."""
return Favorites.objects.by_user(self.request.user) return Favorites.objects.by_user(self.request.user)
@ -15,7 +15,8 @@ class FavoritesBaseView(generics.GenericAPIView):
class FavoritesEstablishmentListView(generics.ListAPIView): class FavoritesEstablishmentListView(generics.ListAPIView):
"""List views for favorites""" """List views for favorites"""
serializer_class = EstablishmentListSerializer
serializer_class = EstablishmentBaseSerializer
def get_queryset(self): def get_queryset(self):
"""Override get_queryset method""" """Override get_queryset method"""

View File

@ -71,6 +71,7 @@ class City(models.Model):
class Address(models.Model): class Address(models.Model):
"""Address model.""" """Address model."""
city = models.ForeignKey(City, verbose_name=_('city'), on_delete=models.CASCADE) city = models.ForeignKey(City, verbose_name=_('city'), on_delete=models.CASCADE)
street_name_1 = models.CharField( street_name_1 = models.CharField(
@ -98,11 +99,11 @@ class Address(models.Model):
@property @property
def latitude(self): def latitude(self):
return self.coordinates.y return self.coordinates.y if self.coordinates else float(0)
@property @property
def longitude(self): def longitude(self):
return self.coordinates.x return self.coordinates.x if self.coordinates else float(0)
@property @property
def location_field_indexing(self): def location_field_indexing(self):

View File

@ -1,11 +1,8 @@
from django.contrib.gis.geos import Point
from rest_framework import serializers
from location import models from location import models
from location.serializers import common from location.serializers import common
class AddressCreateSerializer(common.AddressSerializer): class AddressCreateSerializer(common.AddressDetailSerializer):
"""Address create serializer.""" """Address create serializer."""

View File

@ -1,5 +1,6 @@
"""Location app common serializers.""" """Location app common serializers."""
from django.contrib.gis.geos import Point from django.contrib.gis.geos import Point
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers from rest_framework import serializers
from location import models from location import models
from utils.serializers import TranslatedField from utils.serializers import TranslatedField
@ -83,55 +84,18 @@ class CitySerializer(serializers.ModelSerializer):
] ]
class AddressSerializer(serializers.ModelSerializer): class AddressBaseSerializer(serializers.ModelSerializer):
"""Address serializer."""
city_id = serializers.PrimaryKeyRelatedField(
source='city',
queryset=models.City.objects.all())
city = CitySerializer(read_only=True)
geo_lon = serializers.FloatField(allow_null=True)
geo_lat = serializers.FloatField(allow_null=True)
class Meta:
model = models.Address
fields = [
'id',
'city_id',
'city',
'street_name_1',
'street_name_2',
'number',
'postal_code',
'geo_lon',
'geo_lat',
]
def validate(self, attrs):
# if geo_lat and geo_lon was sent
geo_lat = attrs.pop('geo_lat') if 'geo_lat' in attrs else None
geo_lon = attrs.pop('geo_lon') if 'geo_lon' in attrs else None
if geo_lat and geo_lon:
# Point(longitude, latitude)
attrs['coordinates'] = Point(geo_lat, geo_lon)
return attrs
def to_representation(self, instance):
"""Override to_representation method"""
if instance.coordinates and isinstance(instance.coordinates, Point):
# Point(longitude, latitude)
setattr(instance, 'geo_lat', instance.coordinates.x)
setattr(instance, 'geo_lon', instance.coordinates.y)
else:
setattr(instance, 'geo_lat', float(0))
setattr(instance, 'geo_lon', float(0))
return super().to_representation(instance)
class AddressSimpleSerializer(serializers.ModelSerializer):
"""Serializer for address obj in related objects.""" """Serializer for address obj in related objects."""
latitude = serializers.FloatField(allow_null=True)
longitude = serializers.FloatField(allow_null=True)
# todo: remove this fields (backward compatibility)
geo_lon = serializers.FloatField(source='longitude', allow_null=True,
read_only=True)
geo_lat = serializers.FloatField(source='latitude', allow_null=True,
read_only=True)
class Meta: class Meta:
"""Meta class.""" """Meta class."""
@ -142,4 +106,45 @@ class AddressSimpleSerializer(serializers.ModelSerializer):
'street_name_2', 'street_name_2',
'number', 'number',
'postal_code', 'postal_code',
'latitude',
'longitude',
# todo: remove this fields (backward compatibility)
'geo_lon',
'geo_lat',
)
def validate_latitude(self, value):
if -90 <= value <= 90:
return value
raise serializers.ValidationError(_('Invalid value'))
def validate_longitude(self, value):
if -180 <= value <= 180:
return value
raise serializers.ValidationError(_('Invalid value'))
def validate(self, attrs):
# validate coordinates
latitude = attrs.pop('latitude', None)
longitude = attrs.pop('longitude', None)
if latitude is not None and longitude is not None:
attrs['coordinates'] = Point(longitude, latitude)
return attrs
class AddressDetailSerializer(AddressBaseSerializer):
"""Address serializer."""
city_id = serializers.PrimaryKeyRelatedField(
source='city', write_only=True,
queryset=models.City.objects.all())
city = CitySerializer(read_only=True)
class Meta(AddressBaseSerializer.Meta):
"""Meta class."""
fields = AddressBaseSerializer.Meta.fields + (
'city_id',
'city',
) )

View File

@ -1,6 +1,5 @@
"""Location app views.""" """Location app views."""
from rest_framework import generics from rest_framework import generics
from rest_framework import permissions
from location import models, serializers from location import models, serializers
from location.views import common from location.views import common
@ -9,13 +8,13 @@ from location.views import common
# Address # Address
class AddressListCreateView(common.AddressViewMixin, generics.ListCreateAPIView): class AddressListCreateView(common.AddressViewMixin, generics.ListCreateAPIView):
"""Create view for model Address.""" """Create view for model Address."""
serializer_class = serializers.AddressSerializer serializer_class = serializers.AddressDetailSerializer
queryset = models.Address.objects.all() queryset = models.Address.objects.all()
class AddressRUDView(common.AddressViewMixin, generics.RetrieveUpdateDestroyAPIView): class AddressRUDView(common.AddressViewMixin, generics.RetrieveUpdateDestroyAPIView):
"""RUD view for model Address.""" """RUD view for model Address."""
serializer_class = serializers.AddressSerializer serializer_class = serializers.AddressDetailSerializer
queryset = models.Address.objects.all() queryset = models.Address.objects.all()

View File

@ -100,17 +100,17 @@ class CityUpdateView(CityViewMixin, generics.UpdateAPIView):
# Address # Address
class AddressCreateView(AddressViewMixin, generics.CreateAPIView): class AddressCreateView(AddressViewMixin, generics.CreateAPIView):
"""Create view for model Address""" """Create view for model Address"""
serializer_class = serializers.AddressSerializer serializer_class = serializers.AddressDetailSerializer
class AddressRetrieveView(AddressViewMixin, generics.RetrieveAPIView): class AddressRetrieveView(AddressViewMixin, generics.RetrieveAPIView):
"""Retrieve view for model Address""" """Retrieve view for model Address"""
serializer_class = serializers.AddressSerializer serializer_class = serializers.AddressDetailSerializer
class AddressListView(AddressViewMixin, generics.ListAPIView): class AddressListView(AddressViewMixin, generics.ListAPIView):
"""List view for model Address""" """List view for model Address"""
permission_classes = (permissions.AllowAny, ) permission_classes = (permissions.AllowAny, )
serializer_class = serializers.AddressSerializer serializer_class = serializers.AddressDetailSerializer

View File

@ -318,9 +318,9 @@ class Carousel(models.Model):
@property @property
def vintage_year(self): def vintage_year(self):
if hasattr(self.content_object, 'reviews'): if hasattr(self.content_object, 'reviews'):
review_qs = self.content_object.reviews.by_status(Review.READY) last_review = self.content_object.reviews.by_status(Review.READY).last()
if review_qs.exists(): if last_review:
return review_qs.last().vintage return last_review.vintage
@property @property
def toque_number(self): def toque_number(self):
@ -337,6 +337,16 @@ class Carousel(models.Model):
if hasattr(self.content_object, 'image_url'): if hasattr(self.content_object, 'image_url'):
return self.content_object.image_url return self.content_object.image_url
@property
def slug(self):
if hasattr(self.content_object, 'slug'):
return self.content_object.slug
@property
def the_most_recent_award(self):
if hasattr(self.content_object, 'the_most_recent_award'):
return self.content_object.the_most_recent_award
@property @property
def model_name(self): def model_name(self):
return self.content_object.__class__.__name__ return self.content_object.__class__.__name__

View File

@ -3,6 +3,7 @@ from rest_framework import serializers
from advertisement.serializers.web import AdvertisementSerializer from advertisement.serializers.web import AdvertisementSerializer
from location.serializers import CountrySerializer from location.serializers import CountrySerializer
from main import models from main import models
from establishment.models import Establishment
from utils.serializers import TranslatedField from utils.serializers import TranslatedField
@ -141,6 +142,7 @@ class CarouselListSerializer(serializers.ModelSerializer):
image = serializers.URLField(source='image_url') image = serializers.URLField(source='image_url')
awards = AwardBaseSerializer(many=True) awards = AwardBaseSerializer(many=True)
vintage_year = serializers.IntegerField() vintage_year = serializers.IntegerField()
last_award = AwardBaseSerializer(source='the_most_recent_award', allow_null=True)
class Meta: class Meta:
"""Meta class.""" """Meta class."""
@ -154,6 +156,8 @@ class CarouselListSerializer(serializers.ModelSerializer):
'public_mark', 'public_mark',
'image', 'image',
'vintage_year', 'vintage_year',
'last_award',
'slug',
] ]

View File

@ -9,7 +9,7 @@ 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.serializers import TranslatedField from utils.serializers import TranslatedField, ProjectModelSerializer
class NewsImageSerializer(ImageSerializer): class NewsImageSerializer(ImageSerializer):
@ -41,7 +41,7 @@ class NewsTypeSerializer(serializers.ModelSerializer):
fields = ('id', 'name') fields = ('id', 'name')
class NewsBaseSerializer(serializers.ModelSerializer): class NewsBaseSerializer(ProjectModelSerializer):
"""Base serializer for News model.""" """Base serializer for News model."""
# read only fields # read only fields
@ -74,7 +74,8 @@ class NewsDetailSerializer(NewsBaseSerializer):
description_translated = TranslatedField() description_translated = TranslatedField()
country = CountrySimpleSerializer(read_only=True) country = CountrySimpleSerializer(read_only=True)
author = UserSerializer(source='created_by') # todo: check the data redundancy
author = UserSerializer(source='created_by', read_only=True)
state_display = serializers.CharField(source='get_state_display', state_display = serializers.CharField(source='get_state_display',
read_only=True) read_only=True)

View File

@ -23,11 +23,13 @@ class NewsMixinView:
class NewsListView(NewsMixinView, generics.ListAPIView): class NewsListView(NewsMixinView, generics.ListAPIView):
"""News list view.""" """News list view."""
filter_class = filters.NewsListFilterSet filter_class = filters.NewsListFilterSet
class NewsDetailView(NewsMixinView, generics.RetrieveAPIView): class NewsDetailView(NewsMixinView, generics.RetrieveAPIView):
"""News detail view.""" """News detail view."""
lookup_field = 'slug' lookup_field = 'slug'
serializer_class = serializers.NewsDetailSerializer serializer_class = serializers.NewsDetailSerializer
@ -57,6 +59,7 @@ class NewsBackOfficeLCView(NewsBackOfficeMixinView,
create_serializers_class = serializers.NewsBackOfficeDetailSerializer create_serializers_class = serializers.NewsBackOfficeDetailSerializer
def get_serializer_class(self): def get_serializer_class(self):
"""Override serializer class."""
if self.request.method == 'POST': if self.request.method == 'POST':
return self.create_serializers_class return self.create_serializers_class
return super().get_serializer_class() return super().get_serializer_class()

View File

@ -36,3 +36,4 @@ class Timetable(ProjectBaseMixin):
"""Meta class.""" """Meta class."""
verbose_name = _('Timetable') verbose_name = _('Timetable')
verbose_name_plural = _('Timetables') verbose_name_plural = _('Timetables')
ordering = ['weekday']

View File

@ -1,7 +1,7 @@
"""Utils app serializer.""" """Utils app serializer."""
from rest_framework import serializers
from utils.models import PlatformMixin
from django.core import exceptions from django.core import exceptions
from rest_framework import serializers
from utils import models
from translation.models import Language from translation.models import Language
@ -11,8 +11,8 @@ class EmptySerializer(serializers.Serializer):
class SourceSerializerMixin(serializers.Serializer): class SourceSerializerMixin(serializers.Serializer):
"""Base authorization serializer mixin""" """Base authorization serializer mixin"""
source = serializers.ChoiceField(choices=PlatformMixin.SOURCES, source = serializers.ChoiceField(choices=models.PlatformMixin.SOURCES,
default=PlatformMixin.WEB, default=models.PlatformMixin.WEB,
write_only=True) write_only=True)
@ -25,18 +25,16 @@ class TranslatedField(serializers.CharField):
read_only=read_only, **kwargs) read_only=read_only, **kwargs)
# todo: view validation in more detail
def validate_tjson(value): def validate_tjson(value):
if not isinstance(value, dict): if not isinstance(value, dict):
raise exceptions.ValidationError( raise exceptions.ValidationError(
'invalid_json', 'invalid_json',
code='invalid_json', code='invalid_json',
params={'value': value}, params={'value': value},
) )
lang_count = Language.objects.filter(locale__in=value.keys()).count() lang_count = Language.objects.filter(locale__in=value.keys()).count()
if lang_count != len(value.keys()):
if lang_count == 0:
raise exceptions.ValidationError( raise exceptions.ValidationError(
'invalid_translated_keys', 'invalid_translated_keys',
code='invalid_translated_keys', code='invalid_translated_keys',
@ -44,5 +42,13 @@ def validate_tjson(value):
) )
class TJSONSerializer(serializers.JSONField): class TJSONField(serializers.JSONField):
"""Custom serializer's JSONField for model's TJSONField."""
validators = [validate_tjson] validators = [validate_tjson]
class ProjectModelSerializer(serializers.ModelSerializer):
"""Overrided ModelSerializer."""
serializers.ModelSerializer.serializer_field_mapping[models.TJSONField] = TJSONField

View File

@ -12,8 +12,6 @@ services:
- POSTGRES_DB=postgres - POSTGRES_DB=postgres
ports: ports:
- "5436:5432" - "5436:5432"
networks:
- db-net
volumes: volumes:
- gm-db:/var/lib/postgresql/data/ - gm-db:/var/lib/postgresql/data/
elasticsearch: elasticsearch:
@ -28,8 +26,7 @@ services:
- "ES_JAVA_OPTS=-Xms512m -Xmx512m" - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
- discovery.type=single-node - discovery.type=single-node
- xpack.security.enabled=false - xpack.security.enabled=false
networks:
- app-net
# RabbitMQ # RabbitMQ
rabbitmq: rabbitmq:
image: rabbitmq:latest image: rabbitmq:latest
@ -83,19 +80,12 @@ services:
- worker - worker
- worker_beat - worker_beat
- elasticsearch - elasticsearch
networks:
- app-net
- db-net
volumes: volumes:
- .:/code - .:/code
- gm-media:/media-data - gm-media:/media-data
ports: ports:
- "8000:8000" - "8000:8000"
networks:
app-net:
db-net:
volumes: volumes:
gm-db: gm-db:
name: gm-db name: gm-db

View File

@ -1,5 +1,6 @@
"""Local settings.""" """Local settings."""
from .base import * from .base import *
import sys
ALLOWED_HOSTS = ['*', ] ALLOWED_HOSTS = ['*', ]
@ -57,6 +58,7 @@ LOGGING = {
} }
} }
# ELASTICSEARCH SETTINGS # ELASTICSEARCH SETTINGS
ELASTICSEARCH_DSL = { ELASTICSEARCH_DSL = {
'default': { 'default': {
@ -69,5 +71,10 @@ ELASTICSEARCH_INDEX_NAMES = {
'search_indexes.documents.establishment': 'local_establishment', 'search_indexes.documents.establishment': 'local_establishment',
} }
TESTING = sys.argv[1:2] == ['test']
if TESTING:
ELASTICSEARCH_INDEX_NAMES = {}
# SORL thumbnails # SORL thumbnails
THUMBNAIL_DEBUG = True THUMBNAIL_DEBUG = True