From 1dbd7a6451483042d1d909cd36eafcb2f361f4b7 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 15 Nov 2019 13:01:21 +0300 Subject: [PATCH 1/6] refactored advertisements --- apps/advertisement/admin.py | 7 ++ .../migrations/0006_auto_20191115_0750.py | 34 ++++++++ .../migrations/0007_auto_20191115_0750.py | 30 +++++++ apps/advertisement/models.py | 45 +++++++++- apps/advertisement/serializers/__init__.py | 3 + apps/advertisement/serializers/common.py | 39 +++++++++ apps/advertisement/serializers/mobile.py | 15 ++++ apps/advertisement/serializers/web.py | 31 +++---- apps/advertisement/urls/common.py | 8 ++ apps/advertisement/urls/mobile.py | 14 +++ apps/advertisement/urls/web.py | 5 +- apps/advertisement/views/__init__.py | 3 + apps/advertisement/views/common.py | 32 +++++++ apps/advertisement/views/mobile.py | 9 ++ apps/advertisement/views/web.py | 22 ++--- apps/main/admin.py | 5 ++ .../migrations/0036_auto_20191115_0750.py | 85 +++++++++++++++++++ apps/main/models.py | 71 ++++++++++++---- apps/main/serializers.py | 36 ++++++-- project/settings/base.py | 1 + project/urls/mobile.py | 2 +- project/urls/web.py | 1 + 22 files changed, 433 insertions(+), 65 deletions(-) create mode 100644 apps/advertisement/migrations/0006_auto_20191115_0750.py create mode 100644 apps/advertisement/migrations/0007_auto_20191115_0750.py create mode 100644 apps/advertisement/serializers/common.py create mode 100644 apps/advertisement/serializers/mobile.py create mode 100644 apps/advertisement/urls/common.py create mode 100644 apps/advertisement/urls/mobile.py create mode 100644 apps/advertisement/views/common.py create mode 100644 apps/advertisement/views/mobile.py create mode 100644 apps/main/migrations/0036_auto_20191115_0750.py diff --git a/apps/advertisement/admin.py b/apps/advertisement/admin.py index 74bc6cdc..3754dca9 100644 --- a/apps/advertisement/admin.py +++ b/apps/advertisement/admin.py @@ -2,8 +2,15 @@ from django.contrib import admin from advertisement import models +from main.models import Page + + +class PageInline(admin.TabularInline): + model = Page + extra = 0 @admin.register(models.Advertisement) class AdvertisementModelAdmin(admin.ModelAdmin): """Admin model for model Advertisement""" + inlines = (PageInline, ) diff --git a/apps/advertisement/migrations/0006_auto_20191115_0750.py b/apps/advertisement/migrations/0006_auto_20191115_0750.py new file mode 100644 index 00000000..a043cab2 --- /dev/null +++ b/apps/advertisement/migrations/0006_auto_20191115_0750.py @@ -0,0 +1,34 @@ +# Generated by Django 2.2.7 on 2019-11-15 07:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('advertisement', '0005_auto_20191108_0923'), + ] + + operations = [ + migrations.RemoveField( + model_name='advertisement', + name='height', + ), + migrations.RemoveField( + model_name='advertisement', + name='image_url', + ), + migrations.RemoveField( + model_name='advertisement', + name='source', + ), + migrations.RemoveField( + model_name='advertisement', + name='width', + ), + migrations.AddField( + model_name='advertisement', + name='end', + field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='end'), + ), + ] diff --git a/apps/advertisement/migrations/0007_auto_20191115_0750.py b/apps/advertisement/migrations/0007_auto_20191115_0750.py new file mode 100644 index 00000000..67617b68 --- /dev/null +++ b/apps/advertisement/migrations/0007_auto_20191115_0750.py @@ -0,0 +1,30 @@ +# Generated by Django 2.2.7 on 2019-11-15 07:50 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('advertisement', '0006_auto_20191115_0750'), + ('main', '0036_auto_20191115_0750'), + ] + + operations = [ + migrations.AddField( + model_name='advertisement', + name='page_type', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='advertisements', to='main.PageType', verbose_name='page type'), + ), + migrations.AddField( + model_name='advertisement', + name='sites', + field=models.ManyToManyField(related_name='advertisements', to='main.SiteSettings', verbose_name='site'), + ), + migrations.AddField( + model_name='advertisement', + name='start', + field=models.DateTimeField(null=True, verbose_name='start'), + ), + ] diff --git a/apps/advertisement/models.py b/apps/advertisement/models.py index 3822522d..574aff56 100644 --- a/apps/advertisement/models.py +++ b/apps/advertisement/models.py @@ -6,18 +6,47 @@ from django.utils.translation import gettext_lazy as _ from translation.models import Language from utils.models import ProjectBaseMixin, ImageMixin, PlatformMixin, URLImageMixin +from main.models import Page -class Advertisement(URLImageMixin, ProjectBaseMixin, PlatformMixin): +class AdvertisementQuerySet(models.QuerySet): + """QuerySet for model Advertisement.""" + + def with_base_related(self): + """Return QuerySet with base related""" + return self.select_related('page_type') \ + .prefetch_related('target_languages', 'sites', 'pages') + + def by_page_type(self, page_type: str): + """Filter Advertisement by page type.""" + return self.filter(page_type__name=page_type) + + def by_locale(self, locale): + """Filter by locale.""" + return self.filter(target_languages__locale=locale) + + +class Advertisement(ProjectBaseMixin): """Advertisement model.""" old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) url = models.URLField(verbose_name=_('Ad URL')) - width = models.PositiveIntegerField(verbose_name=_('Block width')) # 300 - height = models.PositiveIntegerField(verbose_name=_('Block height')) # 250 block_level = models.CharField(verbose_name=_('Block level'), max_length=10, blank=True, null=True) target_languages = models.ManyToManyField(Language) + start = models.DateTimeField(null=True, + verbose_name=_('start')) + end = models.DateTimeField(blank=True, null=True, default=None, + verbose_name=_('end')) + sites = models.ManyToManyField('main.SiteSettings', + related_name='advertisements', + verbose_name=_('site')) + page_type = models.ForeignKey('main.PageType', on_delete=models.PROTECT, + null=True, + related_name='advertisements', + verbose_name=_('page type')) + + objects = AdvertisementQuerySet.as_manager() class Meta: verbose_name = _('Advertisement') @@ -25,3 +54,13 @@ class Advertisement(URLImageMixin, ProjectBaseMixin, PlatformMixin): def __str__(self): return str(self.url) + + @property + def mobile_page(self): + """Return mobile page""" + return self.pages.by_platform(Page.MOBILE).first() + + @property + def web_page(self): + """Return web page""" + return self.pages.by_platform(Page.WEB).first() diff --git a/apps/advertisement/serializers/__init__.py b/apps/advertisement/serializers/__init__.py index e69de29b..393379a8 100644 --- a/apps/advertisement/serializers/__init__.py +++ b/apps/advertisement/serializers/__init__.py @@ -0,0 +1,3 @@ +from .common import * +from .mobile import * +from .web import * diff --git a/apps/advertisement/serializers/common.py b/apps/advertisement/serializers/common.py new file mode 100644 index 00000000..8b87abad --- /dev/null +++ b/apps/advertisement/serializers/common.py @@ -0,0 +1,39 @@ +"""Serializers for app advertisements""" +from rest_framework import serializers + +from advertisement import models +from translation.serializers import LanguageSerializer +from main.serializers import SiteShortSerializer +from main.serializers import PageBaseSerializer + + +class AdvertisementBaseSerializer(serializers.ModelSerializer): + """Base serializer for model Advertisement.""" + + languages = LanguageSerializer(many=True, read_only=True) + sites = SiteShortSerializer(many=True, read_only=True) + + class Meta: + model = models.Advertisement + fields = [ + 'id', + 'uuid', + 'url', + 'block_level', + 'languages', + 'sites', + 'start', + 'end', + ] + + +class AdvertisementPageTypeCommonListSerializer(AdvertisementBaseSerializer): + """Serializer for AdvertisementPageTypeCommonView.""" + + page = PageBaseSerializer(source='common_page', read_only=True) + + class Meta(AdvertisementBaseSerializer.Meta): + """Meta class.""" + fields = AdvertisementBaseSerializer.Meta.fields + [ + 'page', + ] diff --git a/apps/advertisement/serializers/mobile.py b/apps/advertisement/serializers/mobile.py new file mode 100644 index 00000000..80a19b82 --- /dev/null +++ b/apps/advertisement/serializers/mobile.py @@ -0,0 +1,15 @@ +"""Serializers for mobile app advertisements""" +from advertisement.serializers import AdvertisementBaseSerializer +from main.serializers import PageBaseSerializer + + +class AdvertisementPageTypeMobileListSerializer(AdvertisementBaseSerializer): + """Serializer for AdvertisementPageTypeMobileView.""" + + page = PageBaseSerializer(source='mobile_page', read_only=True) + + class Meta(AdvertisementBaseSerializer.Meta): + """Meta class.""" + fields = AdvertisementBaseSerializer.Meta.fields + [ + 'page', + ] diff --git a/apps/advertisement/serializers/web.py b/apps/advertisement/serializers/web.py index 6d5ebfc0..175f1875 100644 --- a/apps/advertisement/serializers/web.py +++ b/apps/advertisement/serializers/web.py @@ -1,22 +1,15 @@ -"""Serializers for app advertisements""" -from rest_framework import serializers - -from advertisement import models -from translation.serializers import LanguageSerializer +"""Serializers for web app advertisements""" +from advertisement.serializers import AdvertisementBaseSerializer +from main.serializers import PageBaseSerializer -class AdvertisementSerializer(serializers.ModelSerializer): - """Serializer for model Advertisement.""" +class AdvertisementPageTypeWebListSerializer(AdvertisementBaseSerializer): + """Serializer for AdvertisementPageTypeWebView.""" - class Meta: - model = models.Advertisement - fields = ( - 'id', - 'uuid', - 'url', - 'image_url', - 'width', - 'height', - 'block_level', - 'source' - ) + page = PageBaseSerializer(source='web_page', read_only=True) + + class Meta(AdvertisementBaseSerializer.Meta): + """Meta class.""" + fields = AdvertisementBaseSerializer.Meta.fields + [ + 'page', + ] diff --git a/apps/advertisement/urls/common.py b/apps/advertisement/urls/common.py new file mode 100644 index 00000000..323a3b48 --- /dev/null +++ b/apps/advertisement/urls/common.py @@ -0,0 +1,8 @@ +"""Advertisement common urlpaths.""" +from django.urls import path + + +app_name = 'advertisements' + +common_urlpatterns = [ +] diff --git a/apps/advertisement/urls/mobile.py b/apps/advertisement/urls/mobile.py new file mode 100644 index 00000000..f61003da --- /dev/null +++ b/apps/advertisement/urls/mobile.py @@ -0,0 +1,14 @@ +"""Advertisement common urlpaths.""" +from django.urls import path + +from advertisement.views import mobile as views +from .common import common_urlpatterns + + +app_name = 'advertisements' + +urlpatterns = [ + path('/', views.AdvertisementPageTypeMobileListView.as_view(), name='list'), +] + +urlpatterns += common_urlpatterns diff --git a/apps/advertisement/urls/web.py b/apps/advertisement/urls/web.py index 48f9d71a..4d17c831 100644 --- a/apps/advertisement/urls/web.py +++ b/apps/advertisement/urls/web.py @@ -2,9 +2,12 @@ from django.urls import path from advertisement.views import web as views +from .common import common_urlpatterns app_name = 'advertisements' urlpatterns = [ - path('/', views.AdvertisementListView.as_view(), name='list') + path('/', views.AdvertisementPageTypeWebListView.as_view(), name='list'), ] + +urlpatterns += common_urlpatterns diff --git a/apps/advertisement/views/__init__.py b/apps/advertisement/views/__init__.py index e69de29b..393379a8 100644 --- a/apps/advertisement/views/__init__.py +++ b/apps/advertisement/views/__init__.py @@ -0,0 +1,3 @@ +from .common import * +from .mobile import * +from .web import * diff --git a/apps/advertisement/views/common.py b/apps/advertisement/views/common.py new file mode 100644 index 00000000..43c6e965 --- /dev/null +++ b/apps/advertisement/views/common.py @@ -0,0 +1,32 @@ +"""Views for app advertisement""" +from rest_framework import generics +from rest_framework import permissions + +from advertisement.models import Advertisement +from advertisement.serializers import AdvertisementBaseSerializer, \ + AdvertisementPageTypeCommonListSerializer + + +class AdvertisementBaseView(generics.GenericAPIView): + """Advertisement list view.""" + + pagination_class = None + permission_classes = (permissions.AllowAny, ) + serializer_class = AdvertisementBaseSerializer + + def get_queryset(self): + """Overridden get queryset method.""" + return Advertisement.objects.with_base_related() \ + .by_locale(self.request.locale) + + +class AdvertisementPageTypeListView(AdvertisementBaseView, generics.ListAPIView): + """Advertisement list view by page type.""" + + def get_queryset(self): + """Overridden get queryset method.""" + product_type = self.kwargs.get('page_type') + qs = super(AdvertisementPageTypeListView, self).get_queryset() + if product_type: + return qs.by_page_type(product_type) + return qs.none() diff --git a/apps/advertisement/views/mobile.py b/apps/advertisement/views/mobile.py new file mode 100644 index 00000000..bac5a81d --- /dev/null +++ b/apps/advertisement/views/mobile.py @@ -0,0 +1,9 @@ +"""Mobile views for app advertisement""" +from advertisement.serializers import AdvertisementPageTypeMobileListSerializer +from .common import AdvertisementPageTypeListView + + +class AdvertisementPageTypeMobileListView(AdvertisementPageTypeListView): + """Advertisement mobile list view.""" + + serializer_class = AdvertisementPageTypeMobileListSerializer diff --git a/apps/advertisement/views/web.py b/apps/advertisement/views/web.py index 1740022c..db1cfde8 100644 --- a/apps/advertisement/views/web.py +++ b/apps/advertisement/views/web.py @@ -1,19 +1,9 @@ -"""Views for app advertisement""" -from rest_framework import generics -from rest_framework import permissions - -from advertisement import models -from advertisement.serializers import web as serializers +"""Web views for app advertisement""" +from advertisement.serializers import AdvertisementPageTypeWebListSerializer +from .common import AdvertisementPageTypeListView -class AdvertisementListView(generics.ListAPIView): - """List view for model Advertisement""" - pagination_class = None - model = models.Advertisement - permission_classes = (permissions.AllowAny,) - serializer_class = serializers.AdvertisementSerializer +class AdvertisementPageTypeWebListView(AdvertisementPageTypeListView): + """Advertisement mobile list view.""" - def get_queryset(self): - return models.Advertisement.objects\ - .filter(page__page_name__contains=self.kwargs['page'])\ - .filter(target_languages__locale=self.request.locale) + serializer_class = AdvertisementPageTypeWebListSerializer diff --git a/apps/main/admin.py b/apps/main/admin.py index 77ef20ab..057515e8 100644 --- a/apps/main/admin.py +++ b/apps/main/admin.py @@ -35,3 +35,8 @@ class CurrencyContentAdmin(admin.ModelAdmin): @admin.register(models.Carousel) class CarouselAdmin(admin.ModelAdmin): """Carousel admin.""" + + +@admin.register(models.PageType) +class PageTypeAdmin(admin.ModelAdmin): + """PageType admin.""" diff --git a/apps/main/migrations/0036_auto_20191115_0750.py b/apps/main/migrations/0036_auto_20191115_0750.py new file mode 100644 index 00000000..e429d1e2 --- /dev/null +++ b/apps/main/migrations/0036_auto_20191115_0750.py @@ -0,0 +1,85 @@ +# Generated by Django 2.2.7 on 2019-11-15 07:50 + +from django.db import migrations, models +import django.db.models.deletion +import django.utils.timezone + + +class Migration(migrations.Migration): + + dependencies = [ + ('advertisement', '0006_auto_20191115_0750'), + ('main', '0035_merge_20191112_1218'), + ] + + operations = [ + migrations.CreateModel( + name='PageType', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')), + ('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')), + ('name', models.CharField(max_length=255, unique=True, verbose_name='name')), + ], + options={ + 'verbose_name': 'page type', + 'verbose_name_plural': 'page types', + }, + ), + migrations.AlterModelOptions( + name='page', + options={'verbose_name': 'page', 'verbose_name_plural': 'pages'}, + ), + migrations.RemoveField( + model_name='page', + name='advertisements', + ), + migrations.RemoveField( + model_name='page', + name='page_name', + ), + migrations.AddField( + model_name='page', + name='advertisement', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='pages', to='advertisement.Advertisement', verbose_name='advertisement'), + ), + migrations.AddField( + model_name='page', + name='created', + field=models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created'), + ), + migrations.AddField( + model_name='page', + name='height', + field=models.PositiveIntegerField(null=True, verbose_name='Block height'), + ), + migrations.AddField( + model_name='page', + name='image_url', + field=models.URLField(blank=True, default=None, null=True, verbose_name='Image URL path'), + ), + migrations.AddField( + model_name='page', + name='modified', + field=models.DateTimeField(auto_now=True, verbose_name='Date updated'), + ), + migrations.AddField( + model_name='page', + name='source', + field=models.PositiveSmallIntegerField(choices=[(0, 'Mobile'), (1, 'Web'), (2, 'All')], default=0, verbose_name='Source'), + ), + migrations.AddField( + model_name='page', + name='width', + field=models.PositiveIntegerField(null=True, verbose_name='Block width'), + ), + migrations.RemoveField( + model_name='feature', + name='route', + ), + migrations.AddField( + model_name='feature', + name='route', + field=models.ForeignKey(default=None, null=True, on_delete=django.db.models.deletion.PROTECT, to='main.PageType'), + ), + ] diff --git a/apps/main/models.py b/apps/main/models.py index 310257f3..1bd39a6d 100644 --- a/apps/main/models.py +++ b/apps/main/models.py @@ -10,7 +10,6 @@ from django.db import models from django.db.models import Q from django.utils.translation import gettext_lazy as _ -from advertisement.models import Advertisement from configuration.models import TranslationSettings from location.models import Country from main import methods @@ -99,27 +98,12 @@ class SiteSettings(ProjectBaseMixin): domain=settings.SITE_DOMAIN_URI) -class Page(models.Model): - """Page model.""" - - page_name = models.CharField(max_length=255, unique=True) - advertisements = models.ManyToManyField(Advertisement) - - class Meta: - """Meta class.""" - verbose_name = _('Page') - verbose_name_plural = _('Pages') - - def __str__(self): - return f'{self.page_name}' - - class Feature(ProjectBaseMixin, PlatformMixin): """Feature model.""" slug = models.SlugField(max_length=255, unique=True) priority = models.IntegerField(unique=True, null=True, default=None) - route = models.ForeignKey(Page, on_delete=models.PROTECT, null=True, default=None) + route = models.ForeignKey('PageType', on_delete=models.PROTECT, null=True, default=None) site_settings = models.ManyToManyField(SiteSettings, through='SiteFeature') class Meta: @@ -310,3 +294,56 @@ class Carousel(models.Model): elif self.link not in EMPTY_VALUES: return 'external' return None + + +class PageQuerySet(models.QuerySet): + """QuerySet for model Page.""" + + def by_platform(self, platform: int): + """Filter by platform.""" + return self.filter(source=platform) + + +class Page(URLImageMixin, PlatformMixin, ProjectBaseMixin): + """Page model.""" + advertisement = models.ForeignKey('advertisement.Advertisement', + on_delete=models.PROTECT, null=True, + related_name='pages', + verbose_name=_('advertisement')) + width = models.PositiveIntegerField(null=True, + verbose_name=_('Block width')) # 300 + height = models.PositiveIntegerField(null=True, + verbose_name=_('Block height')) # 250 + + objects = PageQuerySet.as_manager() + + class Meta: + """Meta class.""" + verbose_name = _('page') + verbose_name_plural = _('pages') + + def __str__(self): + """Overridden dunder method.""" + return self.get_source_display() + + +class PageTypeQuerySet(models.QuerySet): + """QuerySet for model PageType.""" + + +class PageType(ProjectBaseMixin): + """Page type model.""" + + name = models.CharField(max_length=255, unique=True, + verbose_name=_('name')) + + objects = PageTypeQuerySet.as_manager() + + class Meta: + """Meta class.""" + verbose_name = _('page type') + verbose_name_plural = _('page types') + + def __str__(self): + """Overridden dunder method.""" + return self.name diff --git a/apps/main/serializers.py b/apps/main/serializers.py index 71bbd589..519ff9de 100644 --- a/apps/main/serializers.py +++ b/apps/main/serializers.py @@ -1,7 +1,6 @@ """Main app serializers.""" from rest_framework import serializers -from advertisement.serializers.web import AdvertisementSerializer from location.serializers import CountrySerializer from main import models from utils.serializers import ProjectModelSerializer, TranslatedField, RecursiveFieldSerializer @@ -94,11 +93,20 @@ class SiteSerializer(serializers.ModelSerializer): class Meta: """Meta class.""" - model = models.SiteSettings fields = ('subdomain', 'site_url', 'country') +class SiteShortSerializer(serializers.ModelSerializer): + """Short serializer for model SiteSettings.""" + + class Meta(SiteSerializer.Meta): + """Meta class.""" + fields = [ + 'subdomain', + ] + + # class SiteFeatureSerializer(serializers.ModelSerializer): # """Site feature serializer.""" # @@ -167,15 +175,27 @@ class CarouselListSerializer(serializers.ModelSerializer): ] -class PageSerializer(serializers.ModelSerializer): - page_name = serializers.CharField() - advertisements = AdvertisementSerializer(source='advertisements', many=True) +class PageBaseSerializer(serializers.ModelSerializer): + """Serializer for model Page""" class Meta: """Meta class.""" - model = models.Carousel + model = models.Page fields = [ 'id', - 'page_name', - 'advertisements' + 'image_url', + 'width', + 'height', ] + + +class PageTypeBaseSerializer(serializers.ModelSerializer): + """Serializer fro model PageType.""" + + class Meta: + """Meta class.""" + model = models.PageType + fields = [ + 'id', + 'name', + ] \ No newline at end of file diff --git a/project/settings/base.py b/project/settings/base.py index 5e3017c7..65ad0954 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -75,6 +75,7 @@ PROJECT_APPS = [ 'favorites.apps.FavoritesConfig', 'rating.apps.RatingConfig', 'tag.apps.TagConfig', + 'transfer.apps.TransferConfig', ] EXTERNAL_APPS = [ diff --git a/project/urls/mobile.py b/project/urls/mobile.py index 8a1558bc..4fa53ad9 100644 --- a/project/urls/mobile.py +++ b/project/urls/mobile.py @@ -9,7 +9,7 @@ urlpatterns = [ path('tags/', include('tag.urls.mobile')), path('timetables/', include('timetable.urls.mobile')), # path('account/', include('account.urls.web')), - # path('advertisement/', include('advertisement.urls.web')), + path('re_blocks/', include('advertisement.urls.mobile')), # path('collection/', include('collection.urls.web')), # path('establishments/', include('establishment.urls.web')), path('news/', include('news.urls.mobile')), diff --git a/project/urls/web.py b/project/urls/web.py index 86f7eac2..c5a609e2 100644 --- a/project/urls/web.py +++ b/project/urls/web.py @@ -36,4 +36,5 @@ urlpatterns = [ path('favorites/', include('favorites.urls')), path('timetables/', include('timetable.urls.web')), path('products/', include('product.urls.web')), + ] From 43fba17288cf3686bfff045cae44898db4df2b11 Mon Sep 17 00:00:00 2001 From: Anatoly Date: Fri, 15 Nov 2019 13:01:56 +0300 Subject: [PATCH 2/6] remove transfer app config --- project/settings/base.py | 1 - 1 file changed, 1 deletion(-) diff --git a/project/settings/base.py b/project/settings/base.py index 65ad0954..5e3017c7 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -75,7 +75,6 @@ PROJECT_APPS = [ 'favorites.apps.FavoritesConfig', 'rating.apps.RatingConfig', 'tag.apps.TagConfig', - 'transfer.apps.TransferConfig', ] EXTERNAL_APPS = [ From 49335c3bc4d3efa465a700b8af5bfb89a9e754dc Mon Sep 17 00:00:00 2001 From: Semyon Date: Wed, 13 Nov 2019 15:28:02 +0300 Subject: [PATCH 3/6] Added establishment type and subtypes to search results --- apps/search_indexes/serializers.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/apps/search_indexes/serializers.py b/apps/search_indexes/serializers.py index 42ea19bc..dffd6e77 100644 --- a/apps/search_indexes/serializers.py +++ b/apps/search_indexes/serializers.py @@ -20,6 +20,19 @@ class TagsDocumentSerializer(serializers.Serializer): return get_translated_value(obj.label) +class EstablishmentTypeSerializer(serializers.Serializer): + """Establishment type serializer for ES Document""" + + id = serializers.IntegerField() + name_translated = serializers.SerializerMethodField() + index_name = serializers.CharField() + + def get_name_translated(self, obj): + if isinstance(obj, dict): + return get_translated_value(obj.get('name')) + return get_translated_value(obj.name) + + class ProductSubtypeDocumentSerializer(serializers.Serializer): """Product subtype serializer for ES Document.""" @@ -149,6 +162,8 @@ class NewsDocumentSerializer(DocumentSerializer): class EstablishmentDocumentSerializer(DocumentSerializer): """Establishment document serializer.""" + establishment_type = EstablishmentTypeSerializer() + establishment_subtypes = EstablishmentTypeSerializer(many=True) address = AddressDocumentSerializer(allow_null=True) tags = TagsDocumentSerializer(many=True) schedule = ScheduleDocumentSerializer(many=True, allow_null=True) From 277fe8d17e2b5558590dafc1e9273ef05f2bc255 Mon Sep 17 00:00:00 2001 From: "a.feteleu" Date: Fri, 15 Nov 2019 13:43:32 +0300 Subject: [PATCH 4/6] fixed SiteFeatureSerializer --- apps/main/serializers.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/main/serializers.py b/apps/main/serializers.py index 519ff9de..0ed2f026 100644 --- a/apps/main/serializers.py +++ b/apps/main/serializers.py @@ -24,7 +24,7 @@ class SiteFeatureSerializer(serializers.ModelSerializer): id = serializers.IntegerField(source='feature.id') slug = serializers.CharField(source='feature.slug') priority = serializers.IntegerField(source='feature.priority') - route = serializers.CharField(source='feature.route.page_name') + route = serializers.CharField(source='feature.route.name') source = serializers.IntegerField(source='feature.source') nested = RecursiveFieldSerializer(many=True, allow_null=True) From 71dd52c19456f786d346a2746488b0985b8d98e9 Mon Sep 17 00:00:00 2001 From: alex Date: Fri, 15 Nov 2019 15:28:27 +0300 Subject: [PATCH 5/6] news in_favs nested fix --- apps/news/models.py | 16 +++---- apps/news/serializers.py | 13 ++++-- apps/notification/transfer_data.py | 14 +++--- apps/transfer/models.py | 2 +- apps/transfer/serializers/notification.py | 53 +++++++++++------------ 5 files changed, 53 insertions(+), 45 deletions(-) diff --git a/apps/news/models.py b/apps/news/models.py index 94b43d0a..550d5baa 100644 --- a/apps/news/models.py +++ b/apps/news/models.py @@ -95,12 +95,14 @@ class NewsQuerySet(TranslationQuerysetMixin): # todo: filter by best score # todo: filter by country? - def should_read(self, news): + def should_read(self, news, user): return self.model.objects.exclude(pk=news.pk).published(). \ + annotate_in_favorites(user). \ with_base_related().by_type(news.news_type).distinct().order_by('?') - def same_theme(self, news): + def same_theme(self, news, user): return self.model.objects.exclude(pk=news.pk).published(). \ + annotate_in_favorites(user). \ with_base_related().by_type(news.news_type). \ by_tags(news.tags.all()).distinct().order_by('-start') @@ -212,13 +214,11 @@ class News(BaseAttributes, TranslatedFieldsMixin): def web_url(self): return reverse('web:news:rud', kwargs={'slug': self.slug}) - @property - def should_read(self): - return self.__class__.objects.should_read(self)[:3] + def should_read(self, user): + return self.__class__.objects.should_read(self, user)[:3] - @property - def same_theme(self): - return self.__class__.objects.same_theme(self)[:3] + def same_theme(self, user): + return self.__class__.objects.same_theme(self, user)[:3] @property def main_image(self): diff --git a/apps/news/serializers.py b/apps/news/serializers.py index fc03a704..7638847f 100644 --- a/apps/news/serializers.py +++ b/apps/news/serializers.py @@ -1,6 +1,7 @@ """News app common serializers.""" from django.utils.translation import gettext_lazy as _ from rest_framework import serializers +from rest_framework.fields import SerializerMethodField from account.serializers.common import UserBaseSerializer from gallery.models import Image @@ -151,7 +152,7 @@ class NewsBaseSerializer(ProjectModelSerializer): 'tags', 'slug', 'in_favorites', - 'view_counter' + 'view_counter', ) @@ -208,8 +209,8 @@ class NewsDetailSerializer(NewsBaseSerializer): class NewsDetailWebSerializer(NewsDetailSerializer): """News detail serializer for web users..""" - same_theme = NewsSimilarListSerializer(many=True, read_only=True) - should_read = NewsSimilarListSerializer(many=True, read_only=True) + same_theme = SerializerMethodField() + should_read = SerializerMethodField() agenda = AgendaSerializer() banner = NewsBannerSerializer() @@ -223,6 +224,12 @@ class NewsDetailWebSerializer(NewsDetailSerializer): 'banner', ) + def get_same_theme(self, obj): + return NewsSimilarListSerializer(obj.same_theme(self.context['request'].user), many=True, read_only=True).data + + def get_should_read(self, obj): + return NewsSimilarListSerializer(obj.should_read(self.context['request'].user), many=True, read_only=True).data + class NewsBackOfficeBaseSerializer(NewsBaseSerializer): """News back office base serializer.""" diff --git a/apps/notification/transfer_data.py b/apps/notification/transfer_data.py index cc5542b4..487501c3 100644 --- a/apps/notification/transfer_data.py +++ b/apps/notification/transfer_data.py @@ -1,5 +1,7 @@ from pprint import pprint +from django.db.models import Count + from transfer.models import EmailAddresses, NewsletterSubscriber from transfer.serializers.notification import SubscriberSerializer, NewsletterSubscriberSerializer @@ -25,12 +27,12 @@ def transfer_newsletter_subscriber(): 'email_address__locale', 'created_at', ) - - serialized_data = NewsletterSubscriberSerializer(data=list(queryset.values()), many=True) - if serialized_data.is_valid(): - serialized_data.save() - else: - pprint(f'NewsletterSubscriber serializer errors: {serialized_data.errors}') + + # serialized_data = NewsletterSubscriberSerializer(data=list(queryset.values()), many=True) + # if serialized_data.is_valid(): + # serialized_data.save() + # else: + # pprint(f'NewsletterSubscriber serializer errors: {serialized_data.errors}') data_types = { diff --git a/apps/transfer/models.py b/apps/transfer/models.py index 25fdb527..29ccb4bd 100644 --- a/apps/transfer/models.py +++ b/apps/transfer/models.py @@ -1201,4 +1201,4 @@ class NewsletterSubscriber(MigrateMixin): class Meta: managed = False - db_table = 'newsletter_subscriber' + db_table = 'newsletter_subscriptions' diff --git a/apps/transfer/serializers/notification.py b/apps/transfer/serializers/notification.py index dc685a0c..7eb7bdac 100644 --- a/apps/transfer/serializers/notification.py +++ b/apps/transfer/serializers/notification.py @@ -1,4 +1,6 @@ from rest_framework import serializers + +from account.models import User from notification.models import Subscriber @@ -44,36 +46,33 @@ class NewsletterSubscriberSerializer(serializers.Serializer): email_address__locale = serializers.CharField(allow_null=True) created_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S') - # def validate(self, data): - # data.update({ - # 'reviewer': self.get_reviewer(data), - # 'status': Review.READY if data['aasm_state'] == 'published' else Review.TO_INVESTIGATE, - # 'published_at': data.pop('created_at'), - # 'old_id': data.pop('id'), - # 'content_object': self.get_establishment(data), - # }) - # data.pop('reviewer_id') - # data.pop('establishment_id') - # data.pop('aasm_state') - # return data - # + def validate(self, data): + data.update({ + 'old_id': data.pop('id'), + 'email': data.pop('email_address__email'), + 'ip_address': data.pop('email_address__ip'), + 'country_code': data.pop('email_address__country_code'), + 'locale': data.pop('email_address__locale'), + 'created': data.pop('created_at'), + 'user_id': self.get_user(data), + }) + data.pop('email_address__account_id') + return data + # def create(self, validated_data): # obj, _ = Review.objects.update_or_create( # old_id=validated_data['old_id'], # defaults=validated_data, # ) # return obj - # - # @staticmethod - # def get_reviewer(data): - # user = User.objects.filter(old_id=data['reviewer_id']).first() - # if not user: - # raise ValueError(f"User account not found with old_id {data['reviewer_id']}") - # return user - # - # @staticmethod - # def get_establishment(data): - # establishment = Establishment.objects.filter(old_id=data['establishment_id']).first() - # if not establishment: - # raise ValueError(f"Establishment not found with old_id {data['establishment_id']}: ") - # return establishment + + @staticmethod + def get_user(data): + + if not data['email_address__account_id']: + return None + + user = User.objects.filter(old_id=data['email_address__account_id']).first() + if not user: + raise ValueError(f"User account not found with old_id {data['email_address__account_id']}") + return user.id From 798e58202c60d5158d396bcaf0daef5d100251ee Mon Sep 17 00:00:00 2001 From: Kuroshini Date: Wed, 16 Oct 2019 14:11:07 +0300 Subject: [PATCH 6/6] Return hardcode for chosen tags --- apps/main/views/common.py | 3 +++ apps/tag/filters.py | 14 ++++++++++++++ apps/tag/views.py | 17 +++++++++++++++++ project/settings/base.py | 6 ++++++ 4 files changed, 40 insertions(+) diff --git a/apps/main/views/common.py b/apps/main/views/common.py index 0c2ef6d4..15f89510 100644 --- a/apps/main/views/common.py +++ b/apps/main/views/common.py @@ -70,6 +70,9 @@ class CarouselListView(generics.ListAPIView): def get_queryset(self): country_code = self.request.country_code + if hasattr(settings, 'CAROUSEL_ITEMS') and country_code in ['www', 'main']: + qs = models.Carousel.objects.filter(id__in=settings.CAROUSEL_ITEMS) + return qs qs = models.Carousel.objects.is_parsed().active() if country_code: qs = qs.by_country_code(country_code) diff --git a/apps/tag/filters.py b/apps/tag/filters.py index c1d6874f..0b1fb829 100644 --- a/apps/tag/filters.py +++ b/apps/tag/filters.py @@ -52,3 +52,17 @@ class TagsFilterSet(TagsBaseFilterSet): model = models.Tag fields = ('type',) + + # TMP TODO remove it later + # Временный хардкод для демонстрации 4 ноября, потом удалить! + def filter_by_type(self, queryset, name, value): + """ Overrides base filter. Temporary decision""" + if not (settings.NEWS_CHOSEN_TAGS and settings.ESTABLISHMENT_CHOSEN_TAGS): + return super().filter_by_type(queryset, name, value) + queryset = models.Tag.objects + if self.NEWS in value: + queryset = queryset.for_news().filter(value__in=settings.NEWS_CHOSEN_TAGS).distinct('value') + if self.ESTABLISHMENT in value: + queryset = queryset.for_establishments().filter(value__in=settings.ESTABLISHMENT_CHOSEN_TAGS).distinct( + 'value') + return queryset diff --git a/apps/tag/views.py b/apps/tag/views.py index c55834e0..4a2f2613 100644 --- a/apps/tag/views.py +++ b/apps/tag/views.py @@ -23,6 +23,23 @@ class ChosenTagsView(generics.ListAPIView, viewsets.GenericViewSet): .filter(id__in=result_tags_ids) \ .order_by_priority() + def list(self, request, *args, **kwargs): + # TMP TODO remove it later + # Временный хардкод для демонстрации > 15 ноября, потом удалить! + queryset = self.filter_queryset(self.get_queryset()) + + page = self.paginate_queryset(queryset) + if page is not None: + serializer = self.get_serializer(page, many=True) + return self.get_paginated_response(serializer.data) + + serializer = self.get_serializer(queryset, many=True) + result_list = serializer.data + if request.query_params.get('type') and (settings.ESTABLISHMENT_CHOSEN_TAGS or settings.NEWS_CHOSEN_TAGS): + ordered_list = settings.ESTABLISHMENT_CHOSEN_TAGS if request.query_params.get('type') == 'establishment' else settings.NEWS_CHOSEN_TAGS + result_list = sorted(result_list, key=lambda x: ordered_list.index(x['index_name'])) + return Response(result_list) + # User`s views & viewsets class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet): diff --git a/project/settings/base.py b/project/settings/base.py index 5e3017c7..85c7960f 100644 --- a/project/settings/base.py +++ b/project/settings/base.py @@ -487,3 +487,9 @@ PHONENUMBER_DB_FORMAT = 'NATIONAL' PHONENUMBER_DEFAULT_REGION = "FR" FALLBACK_LOCALE = 'en-GB' + +# TMP TODO remove it later +# Временный хардкод для демонстрации > 15 ноября, потом удалить! +CAROUSEL_ITEMS = [230, 231, 232] +ESTABLISHMENT_CHOSEN_TAGS = ['gastronomic', 'en_vogue', 'terrace', 'streetfood', 'business', 'bar_cocktail', 'brunch', 'pop'] +NEWS_CHOSEN_TAGS = ['eat', 'drink', 'cook', 'style', 'international', 'event', 'partnership']