From f18c18110cdb46ebc56f8c01b2e65741cc6959e9 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Wed, 25 Sep 2019 15:32:45 +0300 Subject: [PATCH 01/40] Refactor some establishment serializer --- apps/establishment/models.py | 31 ++++++++--- apps/establishment/serializers/back.py | 9 ++- apps/establishment/serializers/common.py | 71 +++++++++++------------- apps/establishment/views/back.py | 11 +++- apps/establishment/views/common.py | 15 ----- apps/establishment/views/web.py | 41 +++++++++----- apps/location/serializers/common.py | 17 +++++- 7 files changed, 112 insertions(+), 83 deletions(-) diff --git a/apps/establishment/models.py b/apps/establishment/models.py index e3384dfb..4ab2fe24 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -13,8 +13,9 @@ from phonenumber_field.modelfields import PhoneNumberField from location.models import Address from collection.models import Collection +from main.models import MetaDataContent from review.models import Review -from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, URLImageMixin, +from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, TranslatedFieldsMixin, BaseAttributes) @@ -70,6 +71,20 @@ class EstablishmentSubType(ProjectBaseMixin, TranslatedFieldsMixin): class EstablishmentQuerySet(models.QuerySet): """Extended queryset for Establishment model.""" + def with_base_related(self): + """Return qs with related objects.""" + return self.select_related('address').prefetch_related( + models.Prefetch('tags', + MetaDataContent.objects.select_related( + 'metadata__category')) + ) + + def with_extended_related(self): + return self.select_related('establishment_type').\ + prefetch_related('establishment_subtypes', 'awards', 'schedule', + 'phones').\ + prefetch_actual_employees() + def search(self, value, locale=None): """Search text in JSON fields.""" if locale is not None: @@ -228,7 +243,7 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin): name = models.CharField(_('name'), max_length=255, default='') name_translated = models.CharField(_('Transliterated name'), - max_length=255, default='') + max_length=255, default='') description = TJSONField(blank=True, null=True, default=None, verbose_name=_('description'), help_text='{"en-GB":"some text"}') @@ -312,12 +327,12 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin): return country.low_price, country.high_price # todo: make via prefetch - @property - def subtypes(self): - return EstablishmentSubType.objects.filter( - subtype_establishment=self, - establishment_type=self.establishment_type, - establishment_type__use_subtypes=True) + # @property + # def subtypes(self): + # return EstablishmentSubType.objects.filter( + # subtype_establishment=self, + # establishment_type=self.establishment_type, + # establishment_type__use_subtypes=True) def set_establishment_type(self, establishment_type): self.establishment_type = establishment_type diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 7013fe6a..17d5f1d5 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -1,12 +1,9 @@ -import json from rest_framework import serializers - from establishment import models -from timetable.models import Timetable from establishment.serializers import ( EstablishmentBaseSerializer, PlateSerializer, ContactEmailsSerializer, - ContactPhonesSerializer, SocialNetworkRelatedSerializers, EstablishmentDetailSerializer -) + ContactPhonesSerializer, SocialNetworkRelatedSerializers, + EstablishmentTypeSerializer) from main.models import Currency @@ -21,6 +18,7 @@ class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): emails = ContactEmailsSerializer(read_only=True, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=True, many=True, ) slug = serializers.SlugField(required=True, allow_blank=False, max_length=50) + type = EstablishmentTypeSerializer(source='establishment_type') class Meta: model = models.Establishment @@ -52,6 +50,7 @@ class EstablishmentRUDSerializer(EstablishmentBaseSerializer): phones = ContactPhonesSerializer(read_only=False, many=True, ) emails = ContactEmailsSerializer(read_only=False, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=False, many=True, ) + type = EstablishmentTypeSerializer(source='establishment_type') class Meta: model = models.Establishment diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 7b974887..f1b2d5ed 100644 --- a/apps/establishment/serializers/common.py +++ b/apps/establishment/serializers/common.py @@ -1,17 +1,17 @@ """Establishment serializers.""" from rest_framework import serializers - +from django.utils.translation import gettext_lazy as _ 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 AddressSerializer +from location.serializers import AddressSimpleSerializer from main.models import MetaDataContent from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer from review import models as review_models from timetable.serialziers import ScheduleRUDSerializer from utils import exceptions as utils_exceptions -from django.utils.translation import gettext_lazy as _ +from utils.serializers import TranslatedField class ContactPhonesSerializer(serializers.ModelSerializer): @@ -142,11 +142,11 @@ class EstablishmentEmployeeSerializer(serializers.ModelSerializer): class EstablishmentBaseSerializer(serializers.ModelSerializer): """Base serializer for Establishment model.""" - type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) - subtypes = EstablishmentSubTypeSerializer(many=True) - address = AddressSerializer() - tags = MetaDataContentSerializer(many=True) + + preview_image = serializers.URLField(source='preview_image_url') slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) + address = AddressSimpleSerializer() + tags = MetaDataContentSerializer(many=True) class Meta: """Meta class.""" @@ -159,60 +159,53 @@ class EstablishmentBaseSerializer(serializers.ModelSerializer): 'price_level', 'toque_number', 'public_mark', - 'type', - 'subtypes', + 'slug', + 'preview_image', + 'in_favorites', 'address', 'tags', - 'slug', ] class EstablishmentListSerializer(EstablishmentBaseSerializer): """Serializer for Establishment model.""" - # Annotated fields + in_favorites = serializers.BooleanField(allow_null=True) - preview_image = serializers.URLField(source='preview_image_url') - - class Meta: + class Meta(EstablishmentBaseSerializer.Meta): """Meta class.""" - model = models.Establishment fields = EstablishmentBaseSerializer.Meta.fields + [ 'in_favorites', - 'preview_image', ] class EstablishmentDetailSerializer(EstablishmentListSerializer): """Serializer for Establishment model.""" - description_translated = serializers.CharField(allow_null=True) + + description_translated = TranslatedField() + image = serializers.URLField(source='image_url') + type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) + subtypes = EstablishmentSubTypeSerializer(many=True, source='establishment_subtypes') awards = AwardSerializer(many=True) schedule = ScheduleRUDSerializer(many=True, allow_null=True) - phones = ContactPhonesSerializer(read_only=True, many=True, ) - emails = ContactEmailsSerializer(read_only=True, many=True, ) + phones = ContactPhonesSerializer(read_only=True, many=True) + emails = ContactEmailsSerializer(read_only=True, many=True) review = serializers.SerializerMethodField() employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees', many=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_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True) - slug = serializers.SlugField(required=True, allow_blank=False, max_length=50) - - in_favorites = serializers.SerializerMethodField() - - image = serializers.URLField(source='image_url') - - class Meta: + class Meta(EstablishmentListSerializer.Meta): """Meta class.""" - model = models.Establishment fields = EstablishmentListSerializer.Meta.fields + [ 'description_translated', - 'price_level', 'image', + 'subtypes', + 'type', 'awards', 'schedule', 'website', @@ -228,23 +221,23 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer): 'best_price_menu', 'best_price_carte', 'transportation', - 'slug', ] + # todo: refactor this s (make as prefetch to model as attr or make as model property) def get_review(self, obj): """Serializer method for getting last published review""" return ReviewSerializer(obj.reviews.by_status(status=review_models.Review.READY) .order_by('-published_at').first()).data - 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 + # 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): diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 974fca8a..78526bdd 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -4,10 +4,17 @@ from rest_framework import generics from establishment import models from establishment import serializers -from establishment.views.common import EstablishmentMixin -class EstablishmentListCreateView(EstablishmentMixin, generics.ListCreateAPIView): +class EstablishmentMixinViews: + """Establishment mixin.""" + + def get_queryset(self): + """Overrided method 'get_queryset'.""" + return models.Establishment.objects.published().with_related() + + +class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAPIView): """Establishment list/create view.""" queryset = models.Establishment.objects.all() serializer_class = serializers.EstablishmentListCreateSerializer diff --git a/apps/establishment/views/common.py b/apps/establishment/views/common.py index b57d6ef6..3029c080 100644 --- a/apps/establishment/views/common.py +++ b/apps/establishment/views/common.py @@ -1,16 +1 @@ """Establishment app views.""" - -from rest_framework import permissions - -from establishment import models - - -class EstablishmentMixin: - """Establishment mixin.""" - - permission_classes = (permissions.AllowAny,) - - def get_queryset(self): - """Overrided method 'get_queryset'.""" - return models.Establishment.objects.published() \ - .prefetch_actual_employees() diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index ce2bed05..3748b95f 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -1,27 +1,47 @@ """Establishment app views.""" - from django.contrib.gis.geos import Point from django.shortcuts import get_object_or_404 from rest_framework import generics, permissions from comment import models as comment_models -from establishment import filters -from establishment import models, serializers -from establishment.views import EstablishmentMixin +from establishment import filters, models, serializers from main.models import MetaDataContent from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer -class EstablishmentListView(EstablishmentMixin, generics.ListAPIView): +class EstablishmentMixinView: + """Establishment mixin.""" + + permission_classes = (permissions.AllowAny,) + + def get_queryset(self): + """Overrided method 'get_queryset'.""" + return models.Establishment.objects.published().with_base_related().\ + annotate_in_favorites(self.request.user) + + +class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView): """Resource for getting a list of establishments.""" - serializer_class = serializers.EstablishmentListSerializer + filter_class = filters.EstablishmentFilter + serializer_class = serializers.EstablishmentListSerializer def get_queryset(self): """Overridden method 'get_queryset'.""" qs = super(EstablishmentListView, self).get_queryset() - return qs.by_country_code(code=self.request.country_code) \ - .annotate_in_favorites(user=self.request.user) + if self.request.country_code: + qs = qs.by_country_code(self.request.country_code) + return qs + + +class EstablishmentRetrieveView(EstablishmentMixinView, generics.RetrieveAPIView): + """Resource for getting a establishment.""" + + lookup_field = 'slug' + serializer_class = serializers.EstablishmentDetailSerializer + + def get_queryset(self): + return super().get_queryset().with_extended_related() class EstablishmentSimilarListView(EstablishmentListView): @@ -33,11 +53,6 @@ class EstablishmentSimilarListView(EstablishmentListView): return super().get_queryset().similar(establishment_slug=self.kwargs.get('slug'))\ .order_by('-total_mark')[:13] -class EstablishmentRetrieveView(EstablishmentMixin, generics.RetrieveAPIView): - """Resource for getting a establishment.""" - lookup_field = 'slug' - serializer_class = serializers.EstablishmentDetailSerializer - class EstablishmentTypeListView(generics.ListAPIView): """Resource for getting a list of establishment types.""" diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 555cf499..1dee92ed 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -1,7 +1,6 @@ """Location app common serializers.""" from django.contrib.gis.geos import Point from rest_framework import serializers - from location import models from utils.serializers import TranslatedField @@ -86,6 +85,7 @@ class CitySerializer(serializers.ModelSerializer): class AddressSerializer(serializers.ModelSerializer): """Address serializer.""" + city_id = serializers.PrimaryKeyRelatedField( source='city', queryset=models.City.objects.all()) @@ -128,3 +128,18 @@ class AddressSerializer(serializers.ModelSerializer): setattr(instance, 'geo_lon', float(0)) return super().to_representation(instance) + +class AddressSimpleSerializer(serializers.ModelSerializer): + """Serializer for address obj in related objects.""" + + class Meta: + """Meta class.""" + + model = models.Address + fields = ( + 'id', + 'street_name_1', + 'street_name_2', + 'number', + 'postal_code', + ) From 6ea876cdc60b6a6022b8f7b48661ada8166f6071 Mon Sep 17 00:00:00 2001 From: Dmitriy Kuzmenko Date: Thu, 26 Sep 2019 11:39:48 +0300 Subject: [PATCH 02/40] test small fix --- apps/collection/tests.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/collection/tests.py b/apps/collection/tests.py index 6a985fc0..4d5ba4ce 100644 --- a/apps/collection/tests.py +++ b/apps/collection/tests.py @@ -20,7 +20,7 @@ class BaseTestCase(APITestCase): self.newsletter = True self.user = User.objects.create_user( username=self.username, email=self.email, password=self.password) - #get tokens + # get tokens tokens = User.create_jwt_tokens(self.user) self.client.cookies = SimpleCookie( {'access_token': tokens.get('access_token'), From f21b4005aa15e5b51cbb03d3f758f8854aebdaf4 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Thu, 26 Sep 2019 16:39:30 +0300 Subject: [PATCH 03/40] address coordinates in get api queries --- apps/location/models.py | 4 ++++ apps/location/serializers/common.py | 20 ++++++++++---------- apps/search_indexes/serializers.py | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/apps/location/models.py b/apps/location/models.py index 7084385f..b0aa298c 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -104,6 +104,10 @@ class Address(models.Model): def longitude(self): return self.coordinates.x + @property + def location(self): + return self.location_field_indexing + @property def location_field_indexing(self): return {'lat': self.latitude, diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 555cf499..0b8ac7ed 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -90,8 +90,9 @@ class AddressSerializer(serializers.ModelSerializer): 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) + geo_lon = serializers.FloatField(allow_null=True, write_only=True) + geo_lat = serializers.FloatField(allow_null=True, write_only=True) + location = serializers.ReadOnlyField() class Meta: model = models.Address @@ -104,7 +105,8 @@ class AddressSerializer(serializers.ModelSerializer): 'number', 'postal_code', 'geo_lon', - 'geo_lat' + 'geo_lat', + 'location', ] def validate(self, attrs): @@ -119,12 +121,10 @@ class AddressSerializer(serializers.ModelSerializer): 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)) + if not instance.coordinates or not isinstance(instance.coordinates, Point): + setattr(instance, 'location', { + 'lat': float(0), + 'lon': float(0), + }) return super().to_representation(instance) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 480f509d..a2ff8d53 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -53,7 +53,7 @@ class EstablishmentDocumentSerializer(DocumentSerializer): fields = ( 'id', 'name', - 'description', + # 'description', 'public_mark', 'toque_number', 'price_level', From 441c16281d6c51a1f879fdb538eab5df816f8181 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Thu, 26 Sep 2019 17:23:55 +0300 Subject: [PATCH 04/40] format api elastic results --- apps/search_indexes/serializers.py | 11 +++++++++++ apps/search_indexes/utils.py | 2 ++ apps/utils/tests.py | 5 +++-- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index a2ff8d53..56af9f5b 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -70,3 +70,14 @@ class EstablishmentDocumentSerializer(DocumentSerializer): @staticmethod def get_description_translated(obj): return get_translated_value(obj.description) + + def to_representation(self, instance): + ret = super().to_representation(instance) + + dict_merge = lambda a, b: a.update(b) or a + ret['tags'] = map(lambda tag: dict_merge(tag, {'label_translated': get_translated_value(tag.pop('label'))}), ret['tags']) + ret['establishment_subtypes'] = map(lambda subtype: dict_merge(subtype, {'name_translated': get_translated_value(subtype.pop('name'))}), ret['establishment_subtypes']) + if ret.get('establishment_type'): + ret['establishment_type']['name_translated'] = get_translated_value(ret['establishment_type'].pop('name')) + ret['address']['city']['country']['name_translated'] = get_translated_value(ret['address']['city']['country'].pop('name')) + return ret \ No newline at end of file diff --git a/apps/search_indexes/utils.py b/apps/search_indexes/utils.py index 93be9e81..0c1dd187 100644 --- a/apps/search_indexes/utils.py +++ b/apps/search_indexes/utils.py @@ -17,4 +17,6 @@ def get_translated_value(value): return None elif not isinstance(value, dict): field_dict = value.to_dict() + elif isinstance(value, dict): + field_dict = value return field_dict.get(get_current_language()) diff --git a/apps/utils/tests.py b/apps/utils/tests.py index 0ca77b6b..5f8df6d8 100644 --- a/apps/utils/tests.py +++ b/apps/utils/tests.py @@ -55,14 +55,15 @@ class TranslateFieldTests(BaseTestCase): start=datetime.now(pytz.utc), end=datetime.now(pytz.utc), is_publish=True, - news_type=self.news_type + news_type=self.news_type, + slug='test', ) def test_model_field(self): self.assertIsNotNone(getattr(self.news_item, "title_translated", None)) def test_read_locale(self): - response = self.client.get(f"/api/web/news/{self.news_item.id}/", format='json') + response = self.client.get(f"/api/web/news/{self.news_item.slug}/", format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) news_data = response.json() From 2fe0ce86d3a6a733fd27716eaaa047d9e365b9a5 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Thu, 26 Sep 2019 17:40:09 +0300 Subject: [PATCH 05/40] Refactor elastic serializer --- apps/search_indexes/serializers.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 56af9f5b..73652ef6 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -46,6 +46,7 @@ class EstablishmentDocumentSerializer(DocumentSerializer): description_translated = serializers.SerializerMethodField(allow_null=True) + preview_image = serializers.URLField(source='preview_image_url') class Meta: """Meta class.""" @@ -63,7 +64,7 @@ class EstablishmentDocumentSerializer(DocumentSerializer): 'collections', 'establishment_type', 'establishment_subtypes', - 'preview_image_url', + 'preview_image', 'slug', ) @@ -73,11 +74,19 @@ class EstablishmentDocumentSerializer(DocumentSerializer): def to_representation(self, instance): ret = super().to_representation(instance) - dict_merge = lambda a, b: a.update(b) or a - ret['tags'] = map(lambda tag: dict_merge(tag, {'label_translated': get_translated_value(tag.pop('label'))}), ret['tags']) - ret['establishment_subtypes'] = map(lambda subtype: dict_merge(subtype, {'name_translated': get_translated_value(subtype.pop('name'))}), ret['establishment_subtypes']) + + ret['tags'] = map(lambda tag: dict_merge(tag, {'label_translated': get_translated_value(tag.pop('label'))}), + ret['tags']) + ret['establishment_subtypes'] = map( + lambda subtype: dict_merge(subtype, {'name_translated': get_translated_value(subtype.pop('name'))}), + ret['establishment_subtypes']) if ret.get('establishment_type'): ret['establishment_type']['name_translated'] = get_translated_value(ret['establishment_type'].pop('name')) - ret['address']['city']['country']['name_translated'] = get_translated_value(ret['address']['city']['country'].pop('name')) + if ret.get('address'): + ret['address']['city']['country']['name_translated'] = get_translated_value( + ret['address']['city']['country'].pop('name')) + + ret['type'] = ret.pop('establishment_type') + ret['subtypes'] = ret.pop('establishment_subtypes') return ret \ No newline at end of file From e0d09486c2f8398e8464323a70c39fc153d1ccc6 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Thu, 26 Sep 2019 17:40:35 +0300 Subject: [PATCH 06/40] Revert "address coordinates in get api queries" This reverts commit f21b400 --- apps/location/models.py | 4 ---- apps/location/serializers/common.py | 20 ++++++++++---------- apps/search_indexes/serializers.py | 2 +- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/apps/location/models.py b/apps/location/models.py index b0aa298c..7084385f 100644 --- a/apps/location/models.py +++ b/apps/location/models.py @@ -104,10 +104,6 @@ class Address(models.Model): def longitude(self): return self.coordinates.x - @property - def location(self): - return self.location_field_indexing - @property def location_field_indexing(self): return {'lat': self.latitude, diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 0b8ac7ed..555cf499 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -90,9 +90,8 @@ class AddressSerializer(serializers.ModelSerializer): source='city', queryset=models.City.objects.all()) city = CitySerializer(read_only=True) - geo_lon = serializers.FloatField(allow_null=True, write_only=True) - geo_lat = serializers.FloatField(allow_null=True, write_only=True) - location = serializers.ReadOnlyField() + geo_lon = serializers.FloatField(allow_null=True) + geo_lat = serializers.FloatField(allow_null=True) class Meta: model = models.Address @@ -105,8 +104,7 @@ class AddressSerializer(serializers.ModelSerializer): 'number', 'postal_code', 'geo_lon', - 'geo_lat', - 'location', + 'geo_lat' ] def validate(self, attrs): @@ -121,10 +119,12 @@ class AddressSerializer(serializers.ModelSerializer): def to_representation(self, instance): """Override to_representation method""" - if not instance.coordinates or not isinstance(instance.coordinates, Point): - setattr(instance, 'location', { - 'lat': float(0), - 'lon': float(0), - }) + 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) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 73652ef6..598b60bf 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -54,7 +54,7 @@ class EstablishmentDocumentSerializer(DocumentSerializer): fields = ( 'id', 'name', - # 'description', + 'description', 'public_mark', 'toque_number', 'price_level', From fec3a2f6bc40bee7524f2912387a168f4873a361 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Thu, 26 Sep 2019 17:46:07 +0300 Subject: [PATCH 07/40] Reformat establishment elastic location for api --- apps/search_indexes/serializers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 598b60bf..925bd6c7 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -86,7 +86,12 @@ class EstablishmentDocumentSerializer(DocumentSerializer): if ret.get('address'): ret['address']['city']['country']['name_translated'] = get_translated_value( ret['address']['city']['country'].pop('name')) + location = ret['address'].pop('location') + if location: + ret['address']['geo_lon'] = location['lon'] + ret['address']['geo_lat'] = location['lat'] ret['type'] = ret.pop('establishment_type') ret['subtypes'] = ret.pop('establishment_subtypes') + return ret \ No newline at end of file From ae00c30fac38d7d1ffb35a4fa29e10eff8d68e66 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Thu, 26 Sep 2019 17:50:07 +0300 Subject: [PATCH 08/40] Fix test --- apps/utils/tests.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/apps/utils/tests.py b/apps/utils/tests.py index 5f8df6d8..4adc2f1e 100644 --- a/apps/utils/tests.py +++ b/apps/utils/tests.py @@ -1,5 +1,5 @@ import pytz -from datetime import datetime +from datetime import datetime, timedelta from rest_framework.test import APITestCase from rest_framework import status @@ -52,8 +52,8 @@ class TranslateFieldTests(BaseTestCase): }, description={"en-GB": "Test description"}, playlist=1, - start=datetime.now(pytz.utc), - end=datetime.now(pytz.utc), + start=datetime.now(pytz.utc) + timedelta(hours=-13), + end=datetime.now(pytz.utc) + timedelta(hours=13), is_publish=True, news_type=self.news_type, slug='test', @@ -63,7 +63,7 @@ class TranslateFieldTests(BaseTestCase): self.assertIsNotNone(getattr(self.news_item, "title_translated", None)) def test_read_locale(self): - response = self.client.get(f"/api/web/news/{self.news_item.slug}/", format='json') + response = self.client.get(f"/api/web/news/slug/{self.news_item.slug}/", format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) news_data = response.json() From 87999830d14915cb2c8c0e3ee0ced48d4cf10c98 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Thu, 26 Sep 2019 17:53:21 +0300 Subject: [PATCH 09/40] Remove description from search results --- apps/search_indexes/serializers.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 925bd6c7..1d8e3ca3 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -54,7 +54,6 @@ class EstablishmentDocumentSerializer(DocumentSerializer): fields = ( 'id', 'name', - 'description', 'public_mark', 'toque_number', 'price_level', From 5793eaad32db7cf90341d2b3d0e349e5a925c949 Mon Sep 17 00:00:00 2001 From: littlewolf Date: Thu, 26 Sep 2019 20:17:50 +0300 Subject: [PATCH 10/40] Add queryset mixin Switch view in urls/common Add homepage view Switch test --- apps/collection/models.py | 4 +++- apps/collection/tests.py | 22 ++++++++++++++++++++++ apps/collection/urls/common.py | 2 +- apps/collection/views/common.py | 24 +++++++++++++++++++++--- apps/utils/querysets.py | 29 +++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 5 deletions(-) diff --git a/apps/collection/models.py b/apps/collection/models.py index beec9b08..25bf1ef9 100644 --- a/apps/collection/models.py +++ b/apps/collection/models.py @@ -8,6 +8,8 @@ from django.utils.translation import gettext_lazy as _ from utils.models import ProjectBaseMixin, URLImageMixin from utils.models import TranslatedFieldsMixin +from utils.querysets import RelatedObjectsCountMixin + # Mixins class CollectionNameMixin(models.Model): @@ -30,7 +32,7 @@ class CollectionDateMixin(models.Model): # Models -class CollectionQuerySet(models.QuerySet): +class CollectionQuerySet(RelatedObjectsCountMixin): """QuerySet for model Collection""" def by_country_code(self, code): diff --git a/apps/collection/tests.py b/apps/collection/tests.py index 6a985fc0..ceb08477 100644 --- a/apps/collection/tests.py +++ b/apps/collection/tests.py @@ -8,6 +8,7 @@ from http.cookies import SimpleCookie from collection.models import Collection, Guide from location.models import Country +from establishment.models import Establishment, EstablishmentType # Create your tests here. @@ -81,3 +82,24 @@ class CollectionGuideDetailTests(CollectionDetailTests): def test_guide_detail_Read(self): response = self.client.get(f'/api/web/collections/guides/{self.guide.id}/', format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) + + +class CollectionWebHomeTests(CollectionDetailTests): + def setUp(self): + super().setUp() + self.establishment_type = EstablishmentType.objects.create(name="Test establishment type") + + self.establishment = Establishment.objects.create( + name="Test establishment", + establishment_type_id=self.establishment_type.id, + is_publish=True, + slug="test" + ) + + self.establishment.collections.add(self.collection) + self.establishment.save() + + def test_collection_list_filter(self): + print("========================================================================================") + response = self.client.get('/api/web/collections/', format='json') + self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/apps/collection/urls/common.py b/apps/collection/urls/common.py index 01385c3d..7ffa50cf 100644 --- a/apps/collection/urls/common.py +++ b/apps/collection/urls/common.py @@ -6,7 +6,7 @@ from collection.views import common as views app_name = 'collection' urlpatterns = [ - path('', views.CollectionListView.as_view(), name='list'), + path('', views.CollectionHomePageView.as_view(), name='list'), path('/establishments/', views.CollectionEstablishmentListView.as_view(), name='detail'), diff --git a/apps/collection/views/common.py b/apps/collection/views/common.py index d42bd851..0818c369 100644 --- a/apps/collection/views/common.py +++ b/apps/collection/views/common.py @@ -30,9 +30,27 @@ class CollectionListView(CollectionViewMixin, generics.ListAPIView): def get_queryset(self): """Override get_queryset method""" - return models.Collection.objects.published()\ - .by_country_code(code=self.request.country_code)\ - .order_by('-on_top', '-created') + queryset = models.Collection.objects.published()\ + .by_country_code(code=self.request.country_code)\ + .order_by('-on_top', '-created') + + return queryset + + +class CollectionHomePageView(CollectionViewMixin, generics.ListAPIView): + """List Collection view""" + permission_classes = (permissions.AllowAny,) + serializer_class = serializers.CollectionSerializer + + def get_queryset(self): + """Override get_queryset method""" + queryset = models.Collection.objects.published()\ + .by_country_code(code=self.request.country_code)\ + .annotate_related_objects_count() \ + .filter_related_gt(3) \ + .order_by('-on_top', '-created') + + return queryset class CollectionEstablishmentListView(CollectionListView): diff --git a/apps/utils/querysets.py b/apps/utils/querysets.py index f25507f7..b6d118a5 100644 --- a/apps/utils/querysets.py +++ b/apps/utils/querysets.py @@ -1,5 +1,6 @@ """Utils QuerySet Mixins""" from django.db import models +from django.db.models import Q from utils.methods import get_contenttype @@ -15,3 +16,31 @@ class ContentTypeQuerySetMixin(models.QuerySet): """Filter QuerySet by ContentType.""" return self.filter(content_type=get_contenttype(app_label=app_label, model=model)) + + +class RelatedObjectsCountMixin(models.QuerySet): + """QuerySet for ManyToMany related count filter""" + + def get_related_objects_names(self): + related_objects_names = [] + + for related_object in self.model._meta.related_objects: + if isinstance(related_object, models.ManyToManyRel): + related_objects_names.append(related_object.name) + + return related_objects_names + + def annotate_related_objects_count(self): + + annotations = {} + for related_object in self.get_related_objects_names(): + annotations[f"{related_object}_count"] = models.Count(f"{related_object}") + + return self.annotate(**annotations) + + def filter_related_gt(self, count): + q_objects = Q() + for related_object in self.get_related_objects_names(): + q_objects.add(Q(**{f"{related_object}_count__gt": count}), Q.OR) + + return self.filter(q_objects) From 4f2bca78f9dc987e6ba17847fc19638681e54513 Mon Sep 17 00:00:00 2001 From: littlewolf Date: Fri, 27 Sep 2019 07:52:57 +0300 Subject: [PATCH 11/40] Update tests Update view --- apps/collection/tests.py | 25 ++++++++++++++----------- apps/collection/views/common.py | 4 ++-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/apps/collection/tests.py b/apps/collection/tests.py index ceb08477..54d7917c 100644 --- a/apps/collection/tests.py +++ b/apps/collection/tests.py @@ -89,17 +89,20 @@ class CollectionWebHomeTests(CollectionDetailTests): super().setUp() self.establishment_type = EstablishmentType.objects.create(name="Test establishment type") - self.establishment = Establishment.objects.create( - name="Test establishment", - establishment_type_id=self.establishment_type.id, - is_publish=True, - slug="test" - ) + for i in range(1, 5): + setattr(self, f"establishment{i}", + Establishment.objects.create( + name=f"Test establishment {i}", + establishment_type_id=self.establishment_type.id, + is_publish=True, + slug=f"test-establishment-{i}" + ) + ) - self.establishment.collections.add(self.collection) - self.establishment.save() + getattr(self, f"establishment{i}").collections.add(self.collection) def test_collection_list_filter(self): - print("========================================================================================") - response = self.client.get('/api/web/collections/', format='json') - self.assertEqual(response.status_code, status.HTTP_200_OK) + response = self.client.get('/api/web/collections/?country_code=en', format='json') + data = response.json() + self.assertIn('count', data) + self.assertGreater(data['count'], 0) diff --git a/apps/collection/views/common.py b/apps/collection/views/common.py index 0818c369..662d35b5 100644 --- a/apps/collection/views/common.py +++ b/apps/collection/views/common.py @@ -46,8 +46,8 @@ class CollectionHomePageView(CollectionViewMixin, generics.ListAPIView): """Override get_queryset method""" queryset = models.Collection.objects.published()\ .by_country_code(code=self.request.country_code)\ - .annotate_related_objects_count() \ - .filter_related_gt(3) \ + .annotate_related_objects_count()\ + .filter_related_gt(3)\ .order_by('-on_top', '-created') return queryset From 44f792db0cd20a427779204317d88d627b59e065 Mon Sep 17 00:00:00 2001 From: littlewolf Date: Fri, 27 Sep 2019 07:58:21 +0300 Subject: [PATCH 12/40] Switch sorting --- apps/collection/views/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/collection/views/common.py b/apps/collection/views/common.py index 662d35b5..f41019ae 100644 --- a/apps/collection/views/common.py +++ b/apps/collection/views/common.py @@ -48,7 +48,7 @@ class CollectionHomePageView(CollectionViewMixin, generics.ListAPIView): .by_country_code(code=self.request.country_code)\ .annotate_related_objects_count()\ .filter_related_gt(3)\ - .order_by('-on_top', '-created') + .order_by('-on_top', '-modified') return queryset From 9608fdb92a45bfdced27d48f1919e14c069e49cb Mon Sep 17 00:00:00 2001 From: michail Date: Fri, 27 Sep 2019 11:30:58 +0500 Subject: [PATCH 13/40] property was added to news model --- apps/news/models.py | 19 +++++++++++++++++++ apps/news/serializers.py | 1 + 2 files changed, 20 insertions(+) diff --git a/apps/news/models.py b/apps/news/models.py index 140c89c9..75deee56 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -5,6 +5,7 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from rest_framework.reverse import reverse from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin +from django.contrib.contenttypes.models import ContentType class NewsType(models.Model): @@ -100,3 +101,21 @@ class News(BaseAttributes, TranslatedFieldsMixin): @property def web_url(self): return reverse('web:news:rud', kwargs={'slug': self.slug}) + + @property + def list_also_like_news(self): + # news_content_type = ContentType.objects.get(app_label="news", model="news") + + # tg_name = self.tags.filter(metadata__content_type=news_content_type) + + # print(tg_name) + + # tag_id = self.tags.all() + # + like_news = News.objects.filter(is_publish=True, news_type=self.news_type, tags__id=self.tags__id) + # + # print("LINE 112", like_news) + + news_list = [self.description, "extra", "field", "test", self.slug] + + return news_list diff --git a/apps/news/serializers.py b/apps/news/serializers.py index dbcd0f62..981ddae0 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -64,6 +64,7 @@ class NewsDetailSerializer(NewsBaseSerializer): 'is_publish', 'author', 'country', + 'list_also_like_news', ) From 962dc2f480b7c1e79808fbe4e0fc48c6d90c80b8 Mon Sep 17 00:00:00 2001 From: michail Date: Fri, 27 Sep 2019 12:01:30 +0500 Subject: [PATCH 14/40] maybe it is solution --- apps/news/models.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/apps/news/models.py b/apps/news/models.py index 75deee56..1b9023db 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -111,11 +111,16 @@ class News(BaseAttributes, TranslatedFieldsMixin): # print(tg_name) # tag_id = self.tags.all() + news_content_type = ContentType.objects.get(app_label="news", model="news") # - like_news = News.objects.filter(is_publish=True, news_type=self.news_type, tags__id=self.tags__id) + like_news = News.objects.filter(is_publish=True, news_type=self.news_type, + tags__content_type=news_content_type) + # # print("LINE 112", like_news) - news_list = [self.description, "extra", "field", "test", self.slug] + # news_list = [self.description, "extra", "field", "test", self.slug] + + news_list = [{"id": n.id, "slug": n.slug} for n in like_news] return news_list From aa037d27f563ecc23e46f398a88f590485f56b65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 27 Sep 2019 10:41:41 +0300 Subject: [PATCH 15/40] Double api --- apps/search_indexes/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/search_indexes/urls.py b/apps/search_indexes/urls.py index 664e0b99..8e914719 100644 --- a/apps/search_indexes/urls.py +++ b/apps/search_indexes/urls.py @@ -6,5 +6,6 @@ from search_indexes import views router = routers.SimpleRouter() # router.register(r'news', views.NewsDocumentViewSet, basename='news') # temporarily disabled router.register(r'establishments', views.EstablishmentDocumentViewSet, basename='establishment') +router.register(r'mobile/establishments', views.EstablishmentDocumentViewSet, basename='establishment-mobile') urlpatterns = router.urls From d115d30e821e5413c7d9bb909ac013e977fcba5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 27 Sep 2019 11:19:49 +0300 Subject: [PATCH 16/40] Fix test authorization --- apps/authorization/tests/tests_authorization.py | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/authorization/tests/tests_authorization.py b/apps/authorization/tests/tests_authorization.py index 4a5d2a2b..d9fd7b71 100644 --- a/apps/authorization/tests/tests_authorization.py +++ b/apps/authorization/tests/tests_authorization.py @@ -22,7 +22,6 @@ def get_tokens_for_user( class AuthorizationTests(APITestCase): def setUp(self): - print("Auth!") data = get_tokens_for_user() self.username = data["username"] self.password = data["password"] From 993e58d215e664b2ef191c9bfbf9f24601dbac40 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Fri, 27 Sep 2019 11:20:43 +0300 Subject: [PATCH 17/40] fix views after merge --- apps/establishment/views/back.py | 2 +- apps/establishment/views/web.py | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/establishment/views/back.py b/apps/establishment/views/back.py index 78526bdd..5cba8255 100644 --- a/apps/establishment/views/back.py +++ b/apps/establishment/views/back.py @@ -11,7 +11,7 @@ class EstablishmentMixinViews: def get_queryset(self): """Overrided method 'get_queryset'.""" - return models.Establishment.objects.published().with_related() + return models.Establishment.objects.published().with_base_related() class EstablishmentListCreateView(EstablishmentMixinViews, generics.ListCreateAPIView): diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index bda64dfb..4ece55c0 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -7,7 +7,6 @@ from rest_framework import generics, permissions from comment import models as comment_models from establishment import filters from establishment import models, serializers -from establishment.views import EstablishmentMixin from main import methods from main.models import MetaDataContent from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer From c7974a75115dae7b7662116d1918e20a66fed644 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 27 Sep 2019 11:33:49 +0300 Subject: [PATCH 18/40] Refactor authorization test --- apps/authorization/tests/tests_authorization.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/apps/authorization/tests/tests_authorization.py b/apps/authorization/tests/tests_authorization.py index d9fd7b71..6028e386 100644 --- a/apps/authorization/tests/tests_authorization.py +++ b/apps/authorization/tests/tests_authorization.py @@ -1,5 +1,6 @@ from rest_framework.test import APITestCase from account.models import User +from django.urls import reverse # Create your tests here. @@ -32,7 +33,9 @@ class AuthorizationTests(APITestCase): 'password': self.password, 'remember': True } - response = self.client.post('/api/auth/login/', data=data) + # login + # /api/auth/login/ + response = self.client.post(reverse('auth:authorization:login'), data=data) self.assertEqual(response.data['access_token'], self.tokens.get('access_token')) self.assertEqual(response.data['refresh_token'], self.tokens.get('refresh_token')) From 62fbded6dea37338579948701a0e8c6d7c7bf19c Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Fri, 27 Sep 2019 11:41:13 +0300 Subject: [PATCH 19/40] added todo --- apps/utils/middleware.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/utils/middleware.py b/apps/utils/middleware.py index 096f8474..f3936169 100644 --- a/apps/utils/middleware.py +++ b/apps/utils/middleware.py @@ -19,6 +19,7 @@ def parse_cookies(get_response): cookie_dict = request.COOKIES # processing locale cookie locale = get_locale(cookie_dict) + # todo: don't use DB!!! Use cache if not Language.objects.filter(locale=locale).exists(): locale = TranslationSettings.get_solo().default_language translation.activate(locale) From fc5ec0920ec3aa5e409d0461cd5c6a109578c488 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 27 Sep 2019 11:43:14 +0300 Subject: [PATCH 20/40] fix --- apps/authorization/tests/tests_authorization.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/apps/authorization/tests/tests_authorization.py b/apps/authorization/tests/tests_authorization.py index 6028e386..a6a49ea5 100644 --- a/apps/authorization/tests/tests_authorization.py +++ b/apps/authorization/tests/tests_authorization.py @@ -33,8 +33,6 @@ class AuthorizationTests(APITestCase): 'password': self.password, 'remember': True } - # login - # /api/auth/login/ response = self.client.post(reverse('auth:authorization:login'), data=data) self.assertEqual(response.data['access_token'], self.tokens.get('access_token')) self.assertEqual(response.data['refresh_token'], self.tokens.get('refresh_token')) From c9bf83fba727745505532d5970cfd40f2bf9767e Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Fri, 27 Sep 2019 11:53:40 +0300 Subject: [PATCH 21/40] News slug, disable null, remove editable --- .../migrations/0014_auto_20190927_0845.py | 21 +++++++++++++++++++ .../migrations/0015_auto_20190927_0853.py | 18 ++++++++++++++++ apps/news/models.py | 4 ++-- 3 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 apps/news/migrations/0014_auto_20190927_0845.py create mode 100644 apps/news/migrations/0015_auto_20190927_0853.py diff --git a/apps/news/migrations/0014_auto_20190927_0845.py b/apps/news/migrations/0014_auto_20190927_0845.py new file mode 100644 index 00000000..270296a4 --- /dev/null +++ b/apps/news/migrations/0014_auto_20190927_0845.py @@ -0,0 +1,21 @@ +# Generated by Django 2.2.4 on 2019-09-27 08:45 +from django.db import migrations + + +def fill_slug(apps,schemaeditor): + News = apps.get_model('news', 'News') + for news in News.objects.all(): + if news.slug is None: + news.slug = f'Slug {news.id}' + news.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0013_auto_20190924_0806'), + ] + + operations = [ + migrations.RunPython(fill_slug, migrations.RunPython.noop) + ] diff --git a/apps/news/migrations/0015_auto_20190927_0853.py b/apps/news/migrations/0015_auto_20190927_0853.py new file mode 100644 index 00000000..e756e2e5 --- /dev/null +++ b/apps/news/migrations/0015_auto_20190927_0853.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-09-27 08:53 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0014_auto_20190927_0845'), + ] + + operations = [ + migrations.AlterField( + model_name='news', + name='slug', + field=models.SlugField(unique=True, verbose_name='News slug'), + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index 140c89c9..4fb8e118 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -63,8 +63,8 @@ class News(BaseAttributes, TranslatedFieldsMixin): start = models.DateTimeField(verbose_name=_('Start')) end = models.DateTimeField(blank=True, null=True, default=None, verbose_name=_('End')) - slug = models.SlugField(unique=True, max_length=50, null=True, - verbose_name=_('News slug'), editable=True,) + slug = models.SlugField(unique=True, max_length=50, + verbose_name=_('News slug')) playlist = models.IntegerField(_('playlist')) is_publish = models.BooleanField(default=False, verbose_name=_('Publish status')) From cd951ddd75f369721eb96d6d75caf4d5e4991a70 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Fri, 27 Sep 2019 11:57:42 +0300 Subject: [PATCH 22/40] remove custom slug field from serializer, small fix in migration --- apps/news/migrations/0014_auto_20190927_0845.py | 2 +- apps/news/serializers.py | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/apps/news/migrations/0014_auto_20190927_0845.py b/apps/news/migrations/0014_auto_20190927_0845.py index 270296a4..dcdee4e4 100644 --- a/apps/news/migrations/0014_auto_20190927_0845.py +++ b/apps/news/migrations/0014_auto_20190927_0845.py @@ -6,7 +6,7 @@ def fill_slug(apps,schemaeditor): News = apps.get_model('news', 'News') for news in News.objects.all(): if news.slug is None: - news.slug = f'Slug {news.id}' + news.slug = f'Slug_{news.id}' news.save() diff --git a/apps/news/serializers.py b/apps/news/serializers.py index dbcd0f62..3d15cff9 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -28,8 +28,6 @@ class NewsBaseSerializer(serializers.ModelSerializer): news_type = NewsTypeSerializer(read_only=True) tags = MetaDataContentSerializer(read_only=True, many=True) - slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) - class Meta: """Meta class.""" From 910322273e72b095862e6a8e8ff7ab23c3296084 Mon Sep 17 00:00:00 2001 From: littlewolf Date: Fri, 27 Sep 2019 12:01:11 +0300 Subject: [PATCH 23/40] Add annotate to filter --- apps/collection/views/common.py | 1 - apps/utils/querysets.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/collection/views/common.py b/apps/collection/views/common.py index f41019ae..80a21be4 100644 --- a/apps/collection/views/common.py +++ b/apps/collection/views/common.py @@ -46,7 +46,6 @@ class CollectionHomePageView(CollectionViewMixin, generics.ListAPIView): """Override get_queryset method""" queryset = models.Collection.objects.published()\ .by_country_code(code=self.request.country_code)\ - .annotate_related_objects_count()\ .filter_related_gt(3)\ .order_by('-on_top', '-modified') diff --git a/apps/utils/querysets.py b/apps/utils/querysets.py index b6d118a5..4937b867 100644 --- a/apps/utils/querysets.py +++ b/apps/utils/querysets.py @@ -43,4 +43,4 @@ class RelatedObjectsCountMixin(models.QuerySet): for related_object in self.get_related_objects_names(): q_objects.add(Q(**{f"{related_object}_count__gt": count}), Q.OR) - return self.filter(q_objects) + return self.annotate_related_objects_count().filter(q_objects) From 46ce25f0f767aafe59a0092e2cd21c8c12342ea3 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Fri, 27 Sep 2019 12:21:50 +0300 Subject: [PATCH 24/40] fix migration --- apps/news/migrations/0014_auto_20190927_0845.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/news/migrations/0014_auto_20190927_0845.py b/apps/news/migrations/0014_auto_20190927_0845.py index dcdee4e4..5a2b35fb 100644 --- a/apps/news/migrations/0014_auto_20190927_0845.py +++ b/apps/news/migrations/0014_auto_20190927_0845.py @@ -1,11 +1,12 @@ # Generated by Django 2.2.4 on 2019-09-27 08:45 from django.db import migrations +from django.core.validators import EMPTY_VALUES def fill_slug(apps,schemaeditor): News = apps.get_model('news', 'News') for news in News.objects.all(): - if news.slug is None: + if news.slug in EMPTY_VALUES: news.slug = f'Slug_{news.id}' news.save() From b55a8ffda6a35886976a971019e4617eca51f04e Mon Sep 17 00:00:00 2001 From: littlewolf Date: Fri, 27 Sep 2019 12:23:12 +0300 Subject: [PATCH 25/40] Add comments --- apps/utils/querysets.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/utils/querysets.py b/apps/utils/querysets.py index 4937b867..1c7dfa84 100644 --- a/apps/utils/querysets.py +++ b/apps/utils/querysets.py @@ -22,6 +22,7 @@ class RelatedObjectsCountMixin(models.QuerySet): """QuerySet for ManyToMany related count filter""" def get_related_objects_names(self): + """Get all related objects (with reversed)""" related_objects_names = [] for related_object in self.model._meta.related_objects: @@ -31,7 +32,7 @@ class RelatedObjectsCountMixin(models.QuerySet): return related_objects_names def annotate_related_objects_count(self): - + """Annotate all related objects to queryset""" annotations = {} for related_object in self.get_related_objects_names(): annotations[f"{related_object}_count"] = models.Count(f"{related_object}") @@ -39,6 +40,7 @@ class RelatedObjectsCountMixin(models.QuerySet): return self.annotate(**annotations) def filter_related_gt(self, count): + """QuerySet filter by related objects count""" q_objects = Q() for related_object in self.get_related_objects_names(): q_objects.add(Q(**{f"{related_object}_count__gt": count}), Q.OR) From 755490c6cf92dc170934bd0126ccbbbe96fdee1a Mon Sep 17 00:00:00 2001 From: michail Date: Fri, 27 Sep 2019 17:12:24 +0500 Subject: [PATCH 26/40] done --- apps/news/models.py | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/apps/news/models.py b/apps/news/models.py index 1b9023db..cfb10d39 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -5,7 +5,7 @@ from django.utils import timezone from django.utils.translation import gettext_lazy as _ from rest_framework.reverse import reverse from utils.models import BaseAttributes, TJSONField, TranslatedFieldsMixin -from django.contrib.contenttypes.models import ContentType +from random import sample as random_sample class NewsType(models.Model): @@ -104,23 +104,18 @@ class News(BaseAttributes, TranslatedFieldsMixin): @property def list_also_like_news(self): - # news_content_type = ContentType.objects.get(app_label="news", model="news") - # tg_name = self.tags.filter(metadata__content_type=news_content_type) + # without "distinct" method the doubles are arising + like_news = News.objects.published().filter(news_type=self.news_type, tags__in=models.F("tags"))\ + .exclude(id=self.id).distinct() - # print(tg_name) + news_count = like_news.count() - # tag_id = self.tags.all() - news_content_type = ContentType.objects.get(app_label="news", model="news") - # - like_news = News.objects.filter(is_publish=True, news_type=self.news_type, - tags__content_type=news_content_type) + if news_count >= 6: + random_ids = random_sample(range(news_count), 6) + else: + random_ids = random_sample(range(news_count), news_count) - # - # print("LINE 112", like_news) - - # news_list = [self.description, "extra", "field", "test", self.slug] - - news_list = [{"id": n.id, "slug": n.slug} for n in like_news] + news_list = [{"id": like_news[r].id, "slug": like_news[r].slug} for r in random_ids] return news_list From 785d2a2f0987ba09c1fd5907245d217097fc75d4 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Fri, 27 Sep 2019 16:56:26 +0300 Subject: [PATCH 27/40] update news serializer, RUD for backoffice --- apps/news/migrations/0016_news_template.py | 18 ++++++++++++++++++ apps/news/models.py | 12 ++++++++++++ apps/news/serializers.py | 5 +++++ 3 files changed, 35 insertions(+) create mode 100644 apps/news/migrations/0016_news_template.py diff --git a/apps/news/migrations/0016_news_template.py b/apps/news/migrations/0016_news_template.py new file mode 100644 index 00000000..f85959ba --- /dev/null +++ b/apps/news/migrations/0016_news_template.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-09-27 13:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0015_auto_20190927_0853'), + ] + + operations = [ + migrations.AddField( + model_name='news', + name='template', + field=models.PositiveIntegerField(choices=[(0, 'newspaper'), (1, 'main.pdf.erb'), (2, 'main')], default=0), + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index 4fb8e118..e0c5fbf4 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -49,6 +49,17 @@ class NewsQuerySet(models.QuerySet): class News(BaseAttributes, TranslatedFieldsMixin): """News model.""" + # template choices + NEWSPAPER = 0 + MAIN_PDF_ERB = 1 + MAIN = 2 + + TEMPLATE_CHOICES = ( + (NEWSPAPER, 'newspaper'), + (MAIN_PDF_ERB, 'main.pdf.erb'), + (MAIN, 'main'), + ) + news_type = models.ForeignKey(NewsType, on_delete=models.PROTECT, verbose_name=_('news type')) title = TJSONField(blank=True, null=True, default=None, @@ -78,6 +89,7 @@ class News(BaseAttributes, TranslatedFieldsMixin): verbose_name=_('Image URL path')) preview_image_url = models.URLField(blank=True, null=True, default=None, verbose_name=_('Preview image URL path')) + template = models.PositiveIntegerField(choices=TEMPLATE_CHOICES, default=NEWSPAPER) address = models.ForeignKey('location.Address', blank=True, null=True, default=None, verbose_name=_('address'), on_delete=models.SET_NULL) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 3d15cff9..82f9980b 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -89,6 +89,9 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer, source='country', write_only=True, queryset=location_models.Country.objects.all()) + template_display = serializers.CharField(source='get_template_display', + read_only=True) + class Meta(NewsBackOfficeBaseSerializer.Meta, NewsDetailSerializer.Meta): """Meta class.""" @@ -97,5 +100,7 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer, 'description', 'news_type_id', 'country_id', + 'template', + 'template_display', ) From ae87a51277fdd38647f16598bc7a35d45ffbe676 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 27 Sep 2019 17:10:08 +0300 Subject: [PATCH 28/40] Author --- apps/news/migrations/0016_remove_news_author.py | 17 +++++++++++++++++ apps/news/models.py | 4 ++-- apps/news/serializers.py | 3 ++- 3 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 apps/news/migrations/0016_remove_news_author.py diff --git a/apps/news/migrations/0016_remove_news_author.py b/apps/news/migrations/0016_remove_news_author.py new file mode 100644 index 00000000..31ad12bb --- /dev/null +++ b/apps/news/migrations/0016_remove_news_author.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.4 on 2019-09-27 13:49 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0015_auto_20190927_0853'), + ] + + operations = [ + migrations.RemoveField( + model_name='news', + name='author', + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index 4fb8e118..545de59d 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -68,8 +68,8 @@ class News(BaseAttributes, TranslatedFieldsMixin): playlist = models.IntegerField(_('playlist')) is_publish = models.BooleanField(default=False, verbose_name=_('Publish status')) - author = models.CharField(max_length=255, blank=True, null=True, - default=None,verbose_name=_('Author')) + # author = models.CharField(max_length=255, blank=True, null=True, + # default=None,verbose_name=_('Author')) is_highlighted = models.BooleanField(default=False, verbose_name=_('Is highlighted')) # TODO: metadata_keys - описание ключей для динамического построения полей метаданных diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 3d15cff9..1778d410 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -5,7 +5,7 @@ from location.serializers import CountrySimpleSerializer from main.serializers import MetaDataContentSerializer from news import models from utils.serializers import TranslatedField - +from account.serializers.common import UserSerializer class NewsTypeSerializer(serializers.ModelSerializer): """News type serializer.""" @@ -50,6 +50,7 @@ class NewsDetailSerializer(NewsBaseSerializer): description_translated = TranslatedField() country = CountrySimpleSerializer(read_only=True) + author = UserSerializer(source='news_records_created') class Meta(NewsBaseSerializer.Meta): """Meta class.""" From a0a6578ae849d5c0b9c96206b9e3ac8d77c0dbdc Mon Sep 17 00:00:00 2001 From: littlewolf Date: Fri, 27 Sep 2019 17:11:42 +0300 Subject: [PATCH 29/40] Add new filter --- apps/collection/views/common.py | 2 +- apps/utils/querysets.py | 21 ++++++++++++++------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/collection/views/common.py b/apps/collection/views/common.py index 80a21be4..148c5fab 100644 --- a/apps/collection/views/common.py +++ b/apps/collection/views/common.py @@ -46,7 +46,7 @@ class CollectionHomePageView(CollectionViewMixin, generics.ListAPIView): """Override get_queryset method""" queryset = models.Collection.objects.published()\ .by_country_code(code=self.request.country_code)\ - .filter_related_gt(3)\ + .filter_all_related_gt(3)\ .order_by('-on_top', '-modified') return queryset diff --git a/apps/utils/querysets.py b/apps/utils/querysets.py index 1c7dfa84..b94cb7b3 100644 --- a/apps/utils/querysets.py +++ b/apps/utils/querysets.py @@ -1,7 +1,8 @@ """Utils QuerySet Mixins""" from django.db import models -from django.db.models import Q - +from django.db.models import Q, Sum, F +from functools import reduce +from operator import add from utils.methods import get_contenttype @@ -21,7 +22,7 @@ class ContentTypeQuerySetMixin(models.QuerySet): class RelatedObjectsCountMixin(models.QuerySet): """QuerySet for ManyToMany related count filter""" - def get_related_objects_names(self): + def _get_related_objects_names(self): """Get all related objects (with reversed)""" related_objects_names = [] @@ -31,10 +32,10 @@ class RelatedObjectsCountMixin(models.QuerySet): return related_objects_names - def annotate_related_objects_count(self): + def _annotate_related_objects_count(self): """Annotate all related objects to queryset""" annotations = {} - for related_object in self.get_related_objects_names(): + for related_object in self._get_related_objects_names(): annotations[f"{related_object}_count"] = models.Count(f"{related_object}") return self.annotate(**annotations) @@ -42,7 +43,13 @@ class RelatedObjectsCountMixin(models.QuerySet): def filter_related_gt(self, count): """QuerySet filter by related objects count""" q_objects = Q() - for related_object in self.get_related_objects_names(): + for related_object in self._get_related_objects_names(): q_objects.add(Q(**{f"{related_object}_count__gt": count}), Q.OR) - return self.annotate_related_objects_count().filter(q_objects) + return self._annotate_related_objects_count().filter(q_objects) + + def filter_all_related_gt(self, count): + exp =reduce(add, [F(f"{related_object}_count") for related_object in self._get_related_objects_names()]) + return self._annotate_related_objects_count()\ + .annotate(all_related_count=exp)\ + .filter(all_related_count__gt=count) From 7a0999a52032a90299e0f6fa36c90d6e63bdfd14 Mon Sep 17 00:00:00 2001 From: littlewolf Date: Fri, 27 Sep 2019 17:12:12 +0300 Subject: [PATCH 30/40] Add new filter --- apps/utils/querysets.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/utils/querysets.py b/apps/utils/querysets.py index b94cb7b3..bf2816f2 100644 --- a/apps/utils/querysets.py +++ b/apps/utils/querysets.py @@ -49,6 +49,7 @@ class RelatedObjectsCountMixin(models.QuerySet): return self._annotate_related_objects_count().filter(q_objects) def filter_all_related_gt(self, count): + """Queryset filter by all related objects count""" exp =reduce(add, [F(f"{related_object}_count") for related_object in self._get_related_objects_names()]) return self._annotate_related_objects_count()\ .annotate(all_related_count=exp)\ From 03753f9059d673138e76b01a9a7f141c76874810 Mon Sep 17 00:00:00 2001 From: evgeniy-st Date: Fri, 27 Sep 2019 17:16:40 +0300 Subject: [PATCH 31/40] News model, state --- .../migrations/0017_auto_20190927_1403.py | 22 ++++++++++++++ apps/news/models.py | 29 ++++++++++++++++--- apps/news/serializers.py | 6 ++-- 3 files changed, 51 insertions(+), 6 deletions(-) create mode 100644 apps/news/migrations/0017_auto_20190927_1403.py diff --git a/apps/news/migrations/0017_auto_20190927_1403.py b/apps/news/migrations/0017_auto_20190927_1403.py new file mode 100644 index 00000000..1886dcec --- /dev/null +++ b/apps/news/migrations/0017_auto_20190927_1403.py @@ -0,0 +1,22 @@ +# Generated by Django 2.2.4 on 2019-09-27 14:03 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0016_news_template'), + ] + + operations = [ + migrations.RemoveField( + model_name='news', + name='is_publish', + ), + migrations.AddField( + model_name='news', + name='state', + field=models.PositiveSmallIntegerField(choices=[(0, 'Waiting'), (1, 'Hidden'), (2, 'Published'), (3, 'Published exclusive')], default=0, verbose_name='State'), + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index e0c5fbf4..9273a1bd 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -39,7 +39,7 @@ class NewsQuerySet(models.QuerySet): now = timezone.now() return self.filter(models.Q(models.Q(end__gte=now) | models.Q(end__isnull=True)), - is_publish=True, start__lte=now) + state__in=[self.model.PUBLISHED_STATES], start__lte=now) def with_related(self): """Return qs with related objects.""" @@ -49,7 +49,9 @@ class NewsQuerySet(models.QuerySet): class News(BaseAttributes, TranslatedFieldsMixin): """News model.""" - # template choices + STR_FIELD_NAME = 'title' + + # TEMPLATE CHOICES NEWSPAPER = 0 MAIN_PDF_ERB = 1 MAIN = 2 @@ -60,6 +62,21 @@ class News(BaseAttributes, TranslatedFieldsMixin): (MAIN, 'main'), ) + # STATE CHOICES + WAITING = 0 + HIDDEN = 1 + PUBLISHED = 2 + PUBLISHED_EXCLUSIVE = 3 + + PUBLISHED_STATES = [PUBLISHED, PUBLISHED_EXCLUSIVE] + + STATE_CHOICES = ( + (WAITING, _('Waiting')), + (HIDDEN, _('Hidden')), + (PUBLISHED, _('Published')), + (PUBLISHED_EXCLUSIVE, _('Published exclusive')), + ) + news_type = models.ForeignKey(NewsType, on_delete=models.PROTECT, verbose_name=_('news type')) title = TJSONField(blank=True, null=True, default=None, @@ -77,8 +94,8 @@ class News(BaseAttributes, TranslatedFieldsMixin): slug = models.SlugField(unique=True, max_length=50, verbose_name=_('News slug')) playlist = models.IntegerField(_('playlist')) - is_publish = models.BooleanField(default=False, - verbose_name=_('Publish status')) + state = models.PositiveSmallIntegerField(default=WAITING, choices=STATE_CHOICES, + verbose_name=_('State')) author = models.CharField(max_length=255, blank=True, null=True, default=None,verbose_name=_('Author')) is_highlighted = models.BooleanField(default=False, @@ -109,6 +126,10 @@ class News(BaseAttributes, TranslatedFieldsMixin): def __str__(self): return f'news: {self.slug}' + @property + def is_publish(self): + return self.state in self.PUBLISHED_STATES + @property def web_url(self): return reverse('web:news:rud', kwargs={'slug': self.slug}) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 82f9980b..2677ce0f 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -50,6 +50,8 @@ class NewsDetailSerializer(NewsBaseSerializer): description_translated = TranslatedField() country = CountrySimpleSerializer(read_only=True) + state_display = serializers.CharField(source='get_state_display', + read_only=True) class Meta(NewsBaseSerializer.Meta): """Meta class.""" @@ -60,6 +62,8 @@ class NewsDetailSerializer(NewsBaseSerializer): 'end', 'playlist', 'is_publish', + 'state', + 'state_display', 'author', 'country', ) @@ -84,11 +88,9 @@ class NewsBackOfficeDetailSerializer(NewsBackOfficeBaseSerializer, news_type_id = serializers.PrimaryKeyRelatedField( source='news_type', write_only=True, queryset=models.NewsType.objects.all()) - country_id = serializers.PrimaryKeyRelatedField( source='country', write_only=True, queryset=location_models.Country.objects.all()) - template_display = serializers.CharField(source='get_template_display', read_only=True) From d25e4af4884235166a8a4a1fd5467fe01b2c5fdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 27 Sep 2019 17:21:57 +0300 Subject: [PATCH 32/40] Created by --- apps/news/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/news/serializers.py b/apps/news/serializers.py index 1778d410..320de8bd 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -50,7 +50,7 @@ class NewsDetailSerializer(NewsBaseSerializer): description_translated = TranslatedField() country = CountrySimpleSerializer(read_only=True) - author = UserSerializer(source='news_records_created') + author = UserSerializer(source='created_by') class Meta(NewsBaseSerializer.Meta): """Meta class.""" From 4f3c8042513dcbfe4bd691fb3cbd2e63d7c910bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Fri, 27 Sep 2019 17:34:13 +0300 Subject: [PATCH 33/40] Fix --- apps/news/migrations/0018_merge_20190927_1432.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 apps/news/migrations/0018_merge_20190927_1432.py diff --git a/apps/news/migrations/0018_merge_20190927_1432.py b/apps/news/migrations/0018_merge_20190927_1432.py new file mode 100644 index 00000000..c4654943 --- /dev/null +++ b/apps/news/migrations/0018_merge_20190927_1432.py @@ -0,0 +1,14 @@ +# Generated by Django 2.2.4 on 2019-09-27 14:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0017_auto_20190927_1403'), + ('news', '0016_remove_news_author'), + ] + + operations = [ + ] From ac8356c7d18da921a21081da672264bff5440361 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 27 Sep 2019 19:03:30 +0300 Subject: [PATCH 34/40] Fix some test && routes && add migration --- apps/favorites/tests.py | 2 +- apps/news/migrations/0019_news_author.py | 18 ++++++++++++++++++ apps/news/models.py | 2 +- apps/news/tests.py | 2 +- apps/utils/tests.py | 2 +- 5 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 apps/news/migrations/0019_news_author.py diff --git a/apps/favorites/tests.py b/apps/favorites/tests.py index 208cf0db..99b01444 100644 --- a/apps/favorites/tests.py +++ b/apps/favorites/tests.py @@ -27,7 +27,7 @@ class BaseTestCase(APITestCase): news_type=self.test_news_type, description={"en-GB": "Description test news"}, playlist=1, start="2020-12-03 12:00:00", end="2020-12-13 12:00:00", - is_publish=True) + state=News.PUBLISHED, slug='test-news') self.test_content_type = ContentType.objects.get(app_label="news", model="news") diff --git a/apps/news/migrations/0019_news_author.py b/apps/news/migrations/0019_news_author.py new file mode 100644 index 00000000..41985255 --- /dev/null +++ b/apps/news/migrations/0019_news_author.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.4 on 2019-09-27 15:32 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('news', '0018_merge_20190927_1432'), + ] + + operations = [ + migrations.AddField( + model_name='news', + name='author', + field=models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='Author'), + ), + ] diff --git a/apps/news/models.py b/apps/news/models.py index 2c6229be..e6967d00 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -39,7 +39,7 @@ class NewsQuerySet(models.QuerySet): now = timezone.now() return self.filter(models.Q(models.Q(end__gte=now) | models.Q(end__isnull=True)), - state__in=[self.model.PUBLISHED_STATES], start__lte=now) + state__in=self.model.PUBLISHED_STATES, start__lte=now) def with_related(self): """Return qs with related objects.""" diff --git a/apps/news/tests.py b/apps/news/tests.py index 7d6724d7..2e24ac45 100644 --- a/apps/news/tests.py +++ b/apps/news/tests.py @@ -26,7 +26,7 @@ class BaseTestCase(APITestCase): news_type=self.test_news_type, description={"en-GB": "Description test news"}, playlist=1, start=datetime.now() + timedelta(hours=-2), end=datetime.now() + timedelta(hours=2), - is_publish=True, slug='test-news-slug',) + state=News.PUBLISHED, slug='test-news-slug',) class NewsTestCase(BaseTestCase): diff --git a/apps/utils/tests.py b/apps/utils/tests.py index 4adc2f1e..10af2a92 100644 --- a/apps/utils/tests.py +++ b/apps/utils/tests.py @@ -54,9 +54,9 @@ class TranslateFieldTests(BaseTestCase): playlist=1, start=datetime.now(pytz.utc) + timedelta(hours=-13), end=datetime.now(pytz.utc) + timedelta(hours=13), - is_publish=True, news_type=self.news_type, slug='test', + state=News.PUBLISHED, ) def test_model_field(self): From d71ed0c1de634dee9335b28efde89f41047e5ff9 Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 27 Sep 2019 19:44:00 +0300 Subject: [PATCH 35/40] Fix lot/lat x/y mapping && address serialization --- apps/establishment/serializers/common.py | 11 +++++++++-- apps/establishment/views/web.py | 2 +- apps/location/serializers/common.py | 2 +- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/apps/establishment/serializers/common.py b/apps/establishment/serializers/common.py index 69a029e2..0e33921c 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 +from location.serializers import AddressSimpleSerializer, AddressSerializer from main.models import MetaDataContent from main.serializers import MetaDataContentSerializer, AwardSerializer, CurrencySerializer from review import models as review_models @@ -146,7 +146,7 @@ class EstablishmentBaseSerializer(serializers.ModelSerializer): preview_image = serializers.URLField(source='preview_image_url') slug = serializers.SlugField(allow_blank=False, required=True, max_length=50) - address = AddressSimpleSerializer() + address = AddressSerializer() tags = MetaDataContentSerializer(many=True) class Meta: @@ -180,6 +180,13 @@ class EstablishmentListSerializer(EstablishmentBaseSerializer): 'in_favorites', ] +class EstablishmentAllListSerializer(EstablishmentListSerializer): + """ Serailizer for api/*/establishments """ + address = AddressSimpleSerializer() + + class Meta(EstablishmentListSerializer.Meta): + pass + class EstablishmentDetailSerializer(EstablishmentListSerializer): """Serializer for Establishment model.""" diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index 4ece55c0..f4558b71 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.EstablishmentListSerializer + serializer_class = serializers.EstablishmentAllListSerializer def get_queryset(self): """Overridden method 'get_queryset'.""" diff --git a/apps/location/serializers/common.py b/apps/location/serializers/common.py index 1dee92ed..37d782de 100644 --- a/apps/location/serializers/common.py +++ b/apps/location/serializers/common.py @@ -104,7 +104,7 @@ class AddressSerializer(serializers.ModelSerializer): 'number', 'postal_code', 'geo_lon', - 'geo_lat' + 'geo_lat', ] def validate(self, attrs): From 1957ab6300bed2c71d3e6d7f0fb4135ee0eaf57e Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 27 Sep 2019 20:54:55 +0300 Subject: [PATCH 36/40] Pagination for ES results --- apps/search_indexes/views.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/search_indexes/views.py b/apps/search_indexes/views.py index 72cab583..0e73ed25 100644 --- a/apps/search_indexes/views.py +++ b/apps/search_indexes/views.py @@ -4,7 +4,8 @@ from django_elasticsearch_dsl_drf import constants from django_elasticsearch_dsl_drf.filter_backends import (FilteringFilterBackend, GeoSpatialFilteringFilterBackend) from django_elasticsearch_dsl_drf.viewsets import BaseDocumentViewSet -from django_elasticsearch_dsl_drf.pagination import PageNumberPagination + +from pagination import ProjectPageNumberPagination from search_indexes import serializers, filters from search_indexes.documents import EstablishmentDocument, NewsDocument @@ -14,7 +15,7 @@ class NewsDocumentViewSet(BaseDocumentViewSet): document = NewsDocument lookup_field = 'slug' - pagination_class = PageNumberPagination + pagination_class = ProjectPageNumberPagination permission_classes = (permissions.AllowAny,) serializer_class = serializers.NewsDocumentSerializer ordering = ('id',) @@ -40,7 +41,7 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet): document = EstablishmentDocument lookup_field = 'slug' - pagination_class = PageNumberPagination + pagination_class = ProjectPageNumberPagination permission_classes = (permissions.AllowAny,) serializer_class = serializers.EstablishmentDocumentSerializer ordering = ('id',) From 4d113a691685b205074ebe765d897c6b26cfb56d Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Fri, 27 Sep 2019 22:06:46 +0300 Subject: [PATCH 37/40] Fix all test --- apps/establishment/serializers/back.py | 2 +- apps/establishment/tests.py | 7 +++++++ apps/utils/tests.py | 3 ++- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/apps/establishment/serializers/back.py b/apps/establishment/serializers/back.py index 788fa1e1..5a15aafc 100644 --- a/apps/establishment/serializers/back.py +++ b/apps/establishment/serializers/back.py @@ -22,7 +22,7 @@ class EstablishmentListCreateSerializer(EstablishmentBaseSerializer): emails = ContactEmailsSerializer(read_only=True, many=True, ) socials = SocialNetworkRelatedSerializers(read_only=True, many=True, ) slug = serializers.SlugField(required=True, allow_blank=False, max_length=50) - type = EstablishmentTypeSerializer(source='establishment_type') + type = EstablishmentTypeSerializer(source='establishment_type', read_only=True) class Meta: model = models.Establishment diff --git a/apps/establishment/tests.py b/apps/establishment/tests.py index 16d224b8..39e28861 100644 --- a/apps/establishment/tests.py +++ b/apps/establishment/tests.py @@ -6,6 +6,7 @@ from http.cookies import SimpleCookie from main.models import Currency from establishment.models import Establishment, EstablishmentType, Menu # Create your tests here. +from translation.models import Language class BaseTestCase(APITestCase): @@ -25,6 +26,12 @@ class BaseTestCase(APITestCase): self.establishment_type = EstablishmentType.objects.create(name="Test establishment type") + # Create lang object + Language.objects.create( + title='English', + locale='en-GB' + ) + class EstablishmentBTests(BaseTestCase): def test_establishment_CRUD(self): diff --git a/apps/utils/tests.py b/apps/utils/tests.py index 10af2a92..0eaf343d 100644 --- a/apps/utils/tests.py +++ b/apps/utils/tests.py @@ -95,6 +95,7 @@ class BaseAttributeTests(BaseTestCase): response_data = response.json() self.assertIn("id", response_data) + self.assertIsInstance(response_data['id'], int) employee = Employee.objects.get(id=response_data['id']) @@ -118,7 +119,7 @@ class BaseAttributeTests(BaseTestCase): 'name': 'Test new name' } - response = self.client.patch('/api/back/establishments/employees/1/', data=update_data) + response = self.client.patch(f'/api/back/establishments/employees/{employee.pk}/', data=update_data) self.assertEqual(response.status_code, status.HTTP_200_OK) employee.refresh_from_db() From 78e1e448d9575b3463a6f95fa65de1e03bbfba19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Mon, 30 Sep 2019 10:09:46 +0300 Subject: [PATCH 38/40] News search --- apps/search_indexes/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/search_indexes/urls.py b/apps/search_indexes/urls.py index 8e914719..a566af1f 100644 --- a/apps/search_indexes/urls.py +++ b/apps/search_indexes/urls.py @@ -7,5 +7,6 @@ router = routers.SimpleRouter() # router.register(r'news', views.NewsDocumentViewSet, basename='news') # temporarily disabled router.register(r'establishments', views.EstablishmentDocumentViewSet, basename='establishment') router.register(r'mobile/establishments', views.EstablishmentDocumentViewSet, basename='establishment-mobile') +router.register(r'news', views.NewsDocumentViewSet, basename='news') urlpatterns = router.urls From 5ef33c0d1920c913ea422691b514d35d4eedbe02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=92=D0=B8=D0=BA=D1=82=D0=BE=D1=80=20=D0=93=D0=BB=D0=B0?= =?UTF-8?q?=D0=B4=D0=BA=D0=B8=D1=85?= Date: Mon, 30 Sep 2019 10:19:09 +0300 Subject: [PATCH 39/40] News search url --- apps/search_indexes/urls.py | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/search_indexes/urls.py b/apps/search_indexes/urls.py index a566af1f..549e569d 100644 --- a/apps/search_indexes/urls.py +++ b/apps/search_indexes/urls.py @@ -10,3 +10,4 @@ router.register(r'mobile/establishments', views.EstablishmentDocumentViewSet, ba router.register(r'news', views.NewsDocumentViewSet, basename='news') urlpatterns = router.urls + From 310928d95cd75ff3b760dd2717920937b768604d Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Mon, 30 Sep 2019 12:46:58 +0300 Subject: [PATCH 40/40] Fix import package issue --- apps/search_indexes/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/search_indexes/views.py b/apps/search_indexes/views.py index 0e73ed25..a69caf1f 100644 --- a/apps/search_indexes/views.py +++ b/apps/search_indexes/views.py @@ -5,7 +5,7 @@ from django_elasticsearch_dsl_drf.filter_backends import (FilteringFilterBackend GeoSpatialFilteringFilterBackend) from django_elasticsearch_dsl_drf.viewsets import BaseDocumentViewSet -from pagination import ProjectPageNumberPagination +from utils.pagination import ProjectPageNumberPagination from search_indexes import serializers, filters from search_indexes.documents import EstablishmentDocument, NewsDocument