diff --git a/apps/collection/tests.py b/apps/collection/tests.py index ea13fff9..72b40c37 100644 --- a/apps/collection/tests.py +++ b/apps/collection/tests.py @@ -1,15 +1,15 @@ -import json, pytz +import json +import pytz 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 collection.models import Collection, Guide -from location.models import Country +from rest_framework import status +from rest_framework.test import APITestCase +from account.models import User +from collection.models import Collection, Guide from establishment.models import Establishment, EstablishmentType -# Create your tests here. +from location.models import Country class BaseTestCase(APITestCase): diff --git a/apps/collection/views/common.py b/apps/collection/views/common.py index 148c5fab..fd2a4584 100644 --- a/apps/collection/views/common.py +++ b/apps/collection/views/common.py @@ -4,7 +4,7 @@ from rest_framework import permissions from collection import models from utils.pagination import ProjectPageNumberPagination 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 @@ -56,7 +56,7 @@ class CollectionEstablishmentListView(CollectionListView): """Retrieve list of establishment for collection.""" permission_classes = (permissions.AllowAny,) pagination_class = ProjectPageNumberPagination - serializer_class = EstablishmentListSerializer + serializer_class = EstablishmentBaseSerializer lookup_field = 'slug' def get_queryset(self): diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index e3857bd7..f09c8200 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -5,7 +5,7 @@ from comment import models as comment_models from comment.serializers import common as comment_serializers from establishment import models from favorites.models import Favorites -from location.serializers import AddressSimpleSerializer, AddressSerializer +from location.serializers import AddressBaseSerializer from main.models import MetaDataContent from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer from review import models as review_models @@ -143,8 +143,9 @@ class EstablishmentBaseSerializer(ProjectModelSerializer): preview_image = serializers.URLField(source='preview_image_url') slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) - address = AddressSerializer() + address = AddressBaseSerializer() tags = MetaDataContentSerializer(many=True) + in_favorites = serializers.BooleanField(allow_null=True) class Meta: """Meta class.""" @@ -165,27 +166,7 @@ class EstablishmentBaseSerializer(ProjectModelSerializer): ] -class EstablishmentListSerializer(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): +class EstablishmentDetailSerializer(EstablishmentBaseSerializer): """Serializer for Establishment model.""" description_translated = TranslatedField() @@ -204,10 +185,10 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer): 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.""" - fields = EstablishmentListSerializer.Meta.fields + [ + fields = EstablishmentBaseSerializer.Meta.fields + [ 'description_translated', 'image', 'subtypes', diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index f4558b71..8f5d2a26 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -28,7 +28,7 @@ class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView): """Resource for getting a list of establishments.""" filter_class = filters.EstablishmentFilter - serializer_class = serializers.EstablishmentAllListSerializer + serializer_class = serializers.EstablishmentBaseSerializer def get_queryset(self): """Overridden method 'get_queryset'.""" @@ -70,7 +70,8 @@ class EstablishmentRecentReviewListView(EstablishmentListView): class EstablishmentSimilarListView(EstablishmentListView): """Resource for getting a list of establishments.""" - serializer_class = serializers.EstablishmentListSerializer + + serializer_class = serializers.EstablishmentBaseSerializer pagination_class = EstablishmentPortionPagination def get_queryset(self): @@ -96,6 +97,7 @@ class EstablishmentCommentCreateView(generics.CreateAPIView): class EstablishmentCommentListView(generics.ListAPIView): """View for return list of establishment comments.""" + permission_classes = (permissions.AllowAny,) serializer_class = serializers.EstablishmentCommentCreateSerializer @@ -153,11 +155,13 @@ class EstablishmentFavoritesCreateDestroyView(generics.CreateAPIView, generics.D class EstablishmentNearestRetrieveView(EstablishmentListView, generics.ListAPIView): """Resource for getting list of nearest establishments.""" - serializer_class = serializers.EstablishmentListSerializer + + serializer_class = serializers.EstablishmentBaseSerializer filter_class = filters.EstablishmentFilter def get_queryset(self): """Overridden method 'get_queryset'.""" + # todo: latitude and longitude lat = self.request.query_params.get('lat') lon = self.request.query_params.get('lon') radius = self.request.query_params.get('radius') diff --git a/apps/favorites/views.py b/apps/favorites/views.py index a80960a8..5d99ed4b 100644 --- a/apps/favorites/views.py +++ b/apps/favorites/views.py @@ -1,13 +1,13 @@ """Views for app favorites.""" from rest_framework import generics - from establishment.models import Establishment -from establishment.serializers import EstablishmentListSerializer +from establishment.serializers import EstablishmentBaseSerializer from .models import Favorites class FavoritesBaseView(generics.GenericAPIView): """Base view for Favorites.""" + def get_queryset(self): """Override get_queryset method.""" return Favorites.objects.by_user(self.request.user) @@ -15,7 +15,8 @@ class FavoritesBaseView(generics.GenericAPIView): class FavoritesEstablishmentListView(generics.ListAPIView): """List views for favorites""" - serializer_class = EstablishmentListSerializer + + serializer_class = EstablishmentBaseSerializer def get_queryset(self): """Override get_queryset method""" diff --git a/apps/location/models.py b/apps/location/models.py index 7084385f..1cab1815 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -71,6 +71,7 @@ class City(models.Model): class Address(models.Model): + """Address model.""" city = models.ForeignKey(City, verbose_name=_('city'), on_delete=models.CASCADE) street_name_1 = models.CharField( @@ -98,11 +99,11 @@ class Address(models.Model): @property def latitude(self): - return self.coordinates.y + return self.coordinates.y if self.coordinates else float(0) @property def longitude(self): - return self.coordinates.x + return self.coordinates.x if self.coordinates else float(0) @property def location_field_indexing(self): diff --git a/apps/location/serializers/back.py b/apps/location/serializers/back.py index f3b36e64..f25aacf6 100644 --- a/apps/location/serializers/back.py +++ b/apps/location/serializers/back.py @@ -1,11 +1,8 @@ -from django.contrib.gis.geos import Point -from rest_framework import serializers - from location import models from location.serializers import common -class AddressCreateSerializer(common.AddressSerializer): +class AddressCreateSerializer(common.AddressDetailSerializer): """Address create serializer.""" diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 37d782de..87d0df4e 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -1,5 +1,6 @@ """Location app common serializers.""" from django.contrib.gis.geos import Point +from django.utils.translation import ugettext_lazy as _ from rest_framework import serializers from location import models from utils.serializers import TranslatedField @@ -83,55 +84,18 @@ class CitySerializer(serializers.ModelSerializer): ] -class AddressSerializer(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): +class AddressBaseSerializer(serializers.ModelSerializer): """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: """Meta class.""" @@ -142,4 +106,45 @@ class AddressSimpleSerializer(serializers.ModelSerializer): 'street_name_2', 'number', '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', ) diff --git a/apps/location/views/back.py b/apps/location/views/back.py index 69ec28bc..ce6589ed 100644 --- a/apps/location/views/back.py +++ b/apps/location/views/back.py @@ -1,6 +1,5 @@ """Location app views.""" from rest_framework import generics -from rest_framework import permissions from location import models, serializers from location.views import common @@ -9,13 +8,13 @@ from location.views import common # Address class AddressListCreateView(common.AddressViewMixin, generics.ListCreateAPIView): """Create view for model Address.""" - serializer_class = serializers.AddressSerializer + serializer_class = serializers.AddressDetailSerializer queryset = models.Address.objects.all() class AddressRUDView(common.AddressViewMixin, generics.RetrieveUpdateDestroyAPIView): """RUD view for model Address.""" - serializer_class = serializers.AddressSerializer + serializer_class = serializers.AddressDetailSerializer queryset = models.Address.objects.all() diff --git a/apps/location/views/common.py b/apps/location/views/common.py index 6bc332ad..792fce91 100644 --- a/apps/location/views/common.py +++ b/apps/location/views/common.py @@ -100,17 +100,17 @@ class CityUpdateView(CityViewMixin, generics.UpdateAPIView): # Address class AddressCreateView(AddressViewMixin, generics.CreateAPIView): """Create view for model Address""" - serializer_class = serializers.AddressSerializer + serializer_class = serializers.AddressDetailSerializer class AddressRetrieveView(AddressViewMixin, generics.RetrieveAPIView): """Retrieve view for model Address""" - serializer_class = serializers.AddressSerializer + serializer_class = serializers.AddressDetailSerializer class AddressListView(AddressViewMixin, generics.ListAPIView): """List view for model Address""" permission_classes = (permissions.AllowAny, ) - serializer_class = serializers.AddressSerializer + serializer_class = serializers.AddressDetailSerializer diff --git a/docker-compose.yml b/docker-compose.yml index 2ccd6de3..7c4e49d2 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,8 +12,6 @@ services: - POSTGRES_DB=postgres ports: - "5436:5432" -# networks: -# - db-net volumes: - gm-db:/var/lib/postgresql/data/ elasticsearch: @@ -28,8 +26,7 @@ services: - "ES_JAVA_OPTS=-Xms512m -Xmx512m" - discovery.type=single-node - xpack.security.enabled=false -# networks: -# - app-net + # RabbitMQ rabbitmq: image: rabbitmq:latest @@ -83,19 +80,12 @@ services: - worker - worker_beat - elasticsearch -# networks: -# - app-net -# - db-net volumes: - .:/code - gm-media:/media-data ports: - "8000:8000" -#networks: -# app-net: -# db-net: - volumes: gm-db: name: gm-db