refactored advertisements

This commit is contained in:
Anatoly 2019-11-15 13:01:21 +03:00
parent 12d44c0a0d
commit 1dbd7a6451
22 changed files with 433 additions and 65 deletions

View File

@ -2,8 +2,15 @@
from django.contrib import admin from django.contrib import admin
from advertisement import models from advertisement import models
from main.models import Page
class PageInline(admin.TabularInline):
model = Page
extra = 0
@admin.register(models.Advertisement) @admin.register(models.Advertisement)
class AdvertisementModelAdmin(admin.ModelAdmin): class AdvertisementModelAdmin(admin.ModelAdmin):
"""Admin model for model Advertisement""" """Admin model for model Advertisement"""
inlines = (PageInline, )

View File

@ -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'),
),
]

View File

@ -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'),
),
]

View File

@ -6,18 +6,47 @@ from django.utils.translation import gettext_lazy as _
from translation.models import Language from translation.models import Language
from utils.models import ProjectBaseMixin, ImageMixin, PlatformMixin, URLImageMixin 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.""" """Advertisement model."""
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None) old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True) uuid = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)
url = models.URLField(verbose_name=_('Ad URL')) 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) block_level = models.CharField(verbose_name=_('Block level'), max_length=10, blank=True, null=True)
target_languages = models.ManyToManyField(Language) 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: class Meta:
verbose_name = _('Advertisement') verbose_name = _('Advertisement')
@ -25,3 +54,13 @@ class Advertisement(URLImageMixin, ProjectBaseMixin, PlatformMixin):
def __str__(self): def __str__(self):
return str(self.url) 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()

View File

@ -0,0 +1,3 @@
from .common import *
from .mobile import *
from .web import *

View File

@ -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',
]

View File

@ -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',
]

View File

@ -1,22 +1,15 @@
"""Serializers for app advertisements""" """Serializers for web app advertisements"""
from rest_framework import serializers from advertisement.serializers import AdvertisementBaseSerializer
from main.serializers import PageBaseSerializer
from advertisement import models
from translation.serializers import LanguageSerializer
class AdvertisementSerializer(serializers.ModelSerializer): class AdvertisementPageTypeWebListSerializer(AdvertisementBaseSerializer):
"""Serializer for model Advertisement.""" """Serializer for AdvertisementPageTypeWebView."""
class Meta: page = PageBaseSerializer(source='web_page', read_only=True)
model = models.Advertisement
fields = ( class Meta(AdvertisementBaseSerializer.Meta):
'id', """Meta class."""
'uuid', fields = AdvertisementBaseSerializer.Meta.fields + [
'url', 'page',
'image_url', ]
'width',
'height',
'block_level',
'source'
)

View File

@ -0,0 +1,8 @@
"""Advertisement common urlpaths."""
from django.urls import path
app_name = 'advertisements'
common_urlpatterns = [
]

View File

@ -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('<page_type>/', views.AdvertisementPageTypeMobileListView.as_view(), name='list'),
]
urlpatterns += common_urlpatterns

View File

@ -2,9 +2,12 @@
from django.urls import path from django.urls import path
from advertisement.views import web as views from advertisement.views import web as views
from .common import common_urlpatterns
app_name = 'advertisements' app_name = 'advertisements'
urlpatterns = [ urlpatterns = [
path('<str:page>/', views.AdvertisementListView.as_view(), name='list') path('<page_type>/', views.AdvertisementPageTypeWebListView.as_view(), name='list'),
] ]
urlpatterns += common_urlpatterns

View File

@ -0,0 +1,3 @@
from .common import *
from .mobile import *
from .web import *

View File

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

View File

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

View File

@ -1,19 +1,9 @@
"""Views for app advertisement""" """Web views for app advertisement"""
from rest_framework import generics from advertisement.serializers import AdvertisementPageTypeWebListSerializer
from rest_framework import permissions from .common import AdvertisementPageTypeListView
from advertisement import models
from advertisement.serializers import web as serializers
class AdvertisementListView(generics.ListAPIView): class AdvertisementPageTypeWebListView(AdvertisementPageTypeListView):
"""List view for model Advertisement""" """Advertisement mobile list view."""
pagination_class = None
model = models.Advertisement
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.AdvertisementSerializer
def get_queryset(self): serializer_class = AdvertisementPageTypeWebListSerializer
return models.Advertisement.objects\
.filter(page__page_name__contains=self.kwargs['page'])\
.filter(target_languages__locale=self.request.locale)

View File

@ -35,3 +35,8 @@ class CurrencyContentAdmin(admin.ModelAdmin):
@admin.register(models.Carousel) @admin.register(models.Carousel)
class CarouselAdmin(admin.ModelAdmin): class CarouselAdmin(admin.ModelAdmin):
"""Carousel admin.""" """Carousel admin."""
@admin.register(models.PageType)
class PageTypeAdmin(admin.ModelAdmin):
"""PageType admin."""

View File

@ -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'),
),
]

View File

@ -10,7 +10,6 @@ from django.db import models
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from advertisement.models import Advertisement
from configuration.models import TranslationSettings from configuration.models import TranslationSettings
from location.models import Country from location.models import Country
from main import methods from main import methods
@ -99,27 +98,12 @@ class SiteSettings(ProjectBaseMixin):
domain=settings.SITE_DOMAIN_URI) 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): class Feature(ProjectBaseMixin, PlatformMixin):
"""Feature model.""" """Feature model."""
slug = models.SlugField(max_length=255, unique=True) slug = models.SlugField(max_length=255, unique=True)
priority = models.IntegerField(unique=True, null=True, default=None) 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') site_settings = models.ManyToManyField(SiteSettings, through='SiteFeature')
class Meta: class Meta:
@ -310,3 +294,56 @@ class Carousel(models.Model):
elif self.link not in EMPTY_VALUES: elif self.link not in EMPTY_VALUES:
return 'external' return 'external'
return None 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

View File

@ -1,7 +1,6 @@
"""Main app serializers.""" """Main app serializers."""
from rest_framework import serializers from rest_framework import serializers
from advertisement.serializers.web import AdvertisementSerializer
from location.serializers import CountrySerializer from location.serializers import CountrySerializer
from main import models from main import models
from utils.serializers import ProjectModelSerializer, TranslatedField, RecursiveFieldSerializer from utils.serializers import ProjectModelSerializer, TranslatedField, RecursiveFieldSerializer
@ -94,11 +93,20 @@ class SiteSerializer(serializers.ModelSerializer):
class Meta: class Meta:
"""Meta class.""" """Meta class."""
model = models.SiteSettings model = models.SiteSettings
fields = ('subdomain', 'site_url', 'country') 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): # class SiteFeatureSerializer(serializers.ModelSerializer):
# """Site feature serializer.""" # """Site feature serializer."""
# #
@ -167,15 +175,27 @@ class CarouselListSerializer(serializers.ModelSerializer):
] ]
class PageSerializer(serializers.ModelSerializer): class PageBaseSerializer(serializers.ModelSerializer):
page_name = serializers.CharField() """Serializer for model Page"""
advertisements = AdvertisementSerializer(source='advertisements', many=True)
class Meta: class Meta:
"""Meta class.""" """Meta class."""
model = models.Carousel model = models.Page
fields = [ fields = [
'id', 'id',
'page_name', 'image_url',
'advertisements' 'width',
'height',
] ]
class PageTypeBaseSerializer(serializers.ModelSerializer):
"""Serializer fro model PageType."""
class Meta:
"""Meta class."""
model = models.PageType
fields = [
'id',
'name',
]

View File

@ -75,6 +75,7 @@ PROJECT_APPS = [
'favorites.apps.FavoritesConfig', 'favorites.apps.FavoritesConfig',
'rating.apps.RatingConfig', 'rating.apps.RatingConfig',
'tag.apps.TagConfig', 'tag.apps.TagConfig',
'transfer.apps.TransferConfig',
] ]
EXTERNAL_APPS = [ EXTERNAL_APPS = [

View File

@ -9,7 +9,7 @@ urlpatterns = [
path('tags/', include('tag.urls.mobile')), path('tags/', include('tag.urls.mobile')),
path('timetables/', include('timetable.urls.mobile')), path('timetables/', include('timetable.urls.mobile')),
# path('account/', include('account.urls.web')), # 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('collection/', include('collection.urls.web')),
# path('establishments/', include('establishment.urls.web')), # path('establishments/', include('establishment.urls.web')),
path('news/', include('news.urls.mobile')), path('news/', include('news.urls.mobile')),

View File

@ -36,4 +36,5 @@ urlpatterns = [
path('favorites/', include('favorites.urls')), path('favorites/', include('favorites.urls')),
path('timetables/', include('timetable.urls.web')), path('timetables/', include('timetable.urls.web')),
path('products/', include('product.urls.web')), path('products/', include('product.urls.web')),
] ]