see changes
This commit is contained in:
parent
cbe03b2f5a
commit
1189b6ff58
49
apps/collection/migrations/0031_auto_20191226_0621.py
Normal file
49
apps/collection/migrations/0031_auto_20191226_0621.py
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-26 06:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
GUIDE_TYPE_RESTAURANT = 0
|
||||
GUIDE_TYPE_WINE = 1
|
||||
|
||||
|
||||
def transform_guide_type(apps, schema_editor):
|
||||
Guide = apps.get_model('collection', 'Guide')
|
||||
to_update = []
|
||||
for guide in Guide.objects.all():
|
||||
if guide.guide_type.name.startswith('restaurant'):
|
||||
guide.guide_type_2 = GUIDE_TYPE_RESTAURANT
|
||||
elif guide.guide_type.name.startswith('wine'):
|
||||
guide.guide_type_2 = GUIDE_TYPE_WINE
|
||||
Guide.objects.bulk_update(to_update, ['guide_type_2', ])
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('collection', '0030_guidefilter_guide_type'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='guidefilter',
|
||||
name='guide_type',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='guide',
|
||||
name='guide_type_2',
|
||||
field=models.PositiveSmallIntegerField(choices=[(0, 'Restaurant'), (1, 'Artisan'), (2, 'Wine')], default=0, verbose_name='guide type'),
|
||||
),
|
||||
migrations.RunPython(transform_guide_type, migrations.RunPython.noop),
|
||||
migrations.RemoveField(
|
||||
model_name='guide',
|
||||
name='guide_type',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='GuideType',
|
||||
),
|
||||
migrations.RenameField(
|
||||
model_name='guide',
|
||||
old_name='guide_type_2',
|
||||
new_name='guide_type',
|
||||
),
|
||||
]
|
||||
|
|
@ -4,20 +4,22 @@ from django.contrib.contenttypes.fields import ContentType
|
|||
from django.contrib.postgres.fields import JSONField
|
||||
from django.core.validators import MaxValueValidator, MinValueValidator
|
||||
from django.db import models
|
||||
from django.conf import settings
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from mptt.models import MPTTModel
|
||||
from mptt.models import MPTTModel, TreeForeignKey
|
||||
from slugify import slugify
|
||||
|
||||
from establishment.models import Establishment
|
||||
from location.models import Country, Region, WineRegion, WineSubRegion, City
|
||||
from review.models import Review
|
||||
from product.models import Product
|
||||
from review.models import Review
|
||||
from collection import tasks
|
||||
from translation.models import Language
|
||||
from utils.methods import slug_into_section_name
|
||||
from utils.models import (
|
||||
ProjectBaseMixin, TJSONField, TranslatedFieldsMixin,
|
||||
URLImageMixin, IntermediateGalleryModelMixin
|
||||
)
|
||||
from utils.methods import slug_into_section_name
|
||||
from utils.querysets import RelatedObjectsCountMixin
|
||||
|
||||
|
||||
|
|
@ -158,28 +160,6 @@ class Collection(ProjectBaseMixin, CollectionDateMixin,
|
|||
super(Collection, self).save(*args, **kwargs)
|
||||
|
||||
|
||||
class GuideTypeQuerySet(models.QuerySet):
|
||||
"""QuerySet for model GuideType."""
|
||||
|
||||
|
||||
class GuideType(ProjectBaseMixin):
|
||||
"""GuideType model."""
|
||||
|
||||
name = models.SlugField(max_length=255, unique=True,
|
||||
verbose_name=_('code'))
|
||||
|
||||
objects = GuideTypeQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
verbose_name = _('guide type')
|
||||
verbose_name_plural = _('guide types')
|
||||
|
||||
def __str__(self):
|
||||
"""Overridden str dunder method."""
|
||||
return self.name
|
||||
|
||||
|
||||
class GuideQuerySet(models.QuerySet):
|
||||
"""QuerySet for Guide."""
|
||||
|
||||
|
|
@ -268,6 +248,19 @@ class Guide(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin):
|
|||
(BUILDING, 'building'),
|
||||
)
|
||||
|
||||
RESTAURANT = 0
|
||||
ARTISAN = 1
|
||||
WINE = 2
|
||||
|
||||
GUIDE_TYPE_CHOICES = (
|
||||
(RESTAURANT, _('Restaurant')),
|
||||
(ARTISAN, _('Artisan')),
|
||||
(WINE, _('Wine')),
|
||||
)
|
||||
|
||||
guide_type = models.PositiveSmallIntegerField(choices=GUIDE_TYPE_CHOICES,
|
||||
default=RESTAURANT,
|
||||
verbose_name=_('guide type'))
|
||||
start = models.DateTimeField(null=True,
|
||||
verbose_name=_('start'))
|
||||
vintage = models.IntegerField(validators=[MinValueValidator(1900),
|
||||
|
|
@ -276,9 +269,6 @@ class Guide(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin):
|
|||
verbose_name=_('guide vintage year'))
|
||||
slug = models.SlugField(max_length=255, unique=True, null=True,
|
||||
verbose_name=_('slug'))
|
||||
guide_type = models.ForeignKey('GuideType', on_delete=models.PROTECT,
|
||||
null=True,
|
||||
verbose_name=_('type'))
|
||||
site = models.ForeignKey('main.SiteSettings', on_delete=models.SET_NULL,
|
||||
null=True,
|
||||
verbose_name=_('site settings'))
|
||||
|
|
@ -301,6 +291,16 @@ class Guide(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin):
|
|||
"""String method."""
|
||||
return f'{self.name}'
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
if not self.pk:
|
||||
if not self.slug:
|
||||
slugify_slug = slugify(
|
||||
f'{self.name} {self.vintage}',
|
||||
word_boundary=True
|
||||
)
|
||||
self.slug = slugify_slug
|
||||
super(Guide, self).save(*args, **kwargs)
|
||||
|
||||
# todo: for test use, use annotation instead
|
||||
# @property
|
||||
# def restaurant_counter_prop(self):
|
||||
|
|
@ -351,6 +351,43 @@ class Guide(ProjectBaseMixin, CollectionNameMixin, CollectionDateMixin):
|
|||
self.count_related_objects = updated_count
|
||||
self.save()
|
||||
|
||||
def generate_elements(self):
|
||||
if self.guidefilter:
|
||||
if self.guide_type in [self.ARTISAN, self.RESTAURANT]:
|
||||
if settings.USE_CELERY:
|
||||
tasks.generate_establishment_guide_elements.delay(
|
||||
guide_id=self.id,
|
||||
queryset_values=self.guidefilter.filtered_queryset_values,
|
||||
section_node_name='RestaurantSectionNode' if self.RESTAURANT else self.ARTISAN
|
||||
)
|
||||
else:
|
||||
tasks.generate_establishment_guide_elements(
|
||||
guide_id=self.id,
|
||||
queryset_values=self.guidefilter.filtered_queryset_values,
|
||||
section_node_name='RestaurantSectionNode' if self.RESTAURANT else self.ARTISAN
|
||||
)
|
||||
elif self.guide_type == self.WINE:
|
||||
if settings.USE_CELERY:
|
||||
tasks.generate_product_guide_elements.delay(
|
||||
guide_id=self.id,
|
||||
queryset_values=self.guidefilter.filtered_queryset_values,
|
||||
)
|
||||
else:
|
||||
tasks.generate_product_guide_elements(
|
||||
guide_id=self.id,
|
||||
queryset_values=self.guidefilter.filtered_queryset_values,
|
||||
)
|
||||
|
||||
def regenerate_elements(self):
|
||||
# get Root node
|
||||
root_node = GuideElement.objects.get_root_node(self)
|
||||
# get all descendants related to this guide and delete it
|
||||
root_node.get_descendants().delete()
|
||||
# re-generate elements
|
||||
self.generate_elements()
|
||||
# update count elements
|
||||
self.update_count_related_objects()
|
||||
|
||||
|
||||
class AdvertorialQuerySet(models.QuerySet):
|
||||
"""QuerySet for model Advertorial."""
|
||||
|
|
@ -384,19 +421,6 @@ class GuideFilterQuerySet(models.QuerySet):
|
|||
class GuideFilter(ProjectBaseMixin):
|
||||
"""Guide filter model."""
|
||||
|
||||
RESTAURANT = 0
|
||||
ARTISAN = 1
|
||||
WINE = 2
|
||||
|
||||
GUIDE_TYPES = (
|
||||
(RESTAURANT, _('Restaurant')),
|
||||
(ARTISAN, _('Artisan')),
|
||||
(WINE, _('Wine')),
|
||||
)
|
||||
|
||||
guide_type = models.PositiveSmallIntegerField(choices=GUIDE_TYPES,
|
||||
default=RESTAURANT,
|
||||
verbose_name=_('guide type'))
|
||||
establishment_type_json = JSONField(blank=True, null=True,
|
||||
verbose_name='establishment types')
|
||||
country_json = JSONField(blank=True, null=True,
|
||||
|
|
@ -645,11 +669,15 @@ class GuideFilter(ProjectBaseMixin):
|
|||
return filters
|
||||
|
||||
@property
|
||||
def filter_set(self):
|
||||
if self.guide_type in [self.RESTAURANT, self.ARTISAN]:
|
||||
return self.establishment_filter_set
|
||||
elif self.guide_type == self.WINE:
|
||||
return self.product_filter_set
|
||||
def filtered_queryset_values(self):
|
||||
if self.guide.guide_type in [self.guide.RESTAURANT, self.guide.ARTISAN]:
|
||||
fields = Establishment._meta.get_all_field_names()
|
||||
fields.pop('tz')
|
||||
return Establishment.objects.filter(**self.establishment_filter_set) \
|
||||
.values_list()[0]
|
||||
elif self.guide.guide_type == self.guide.WINE:
|
||||
return Product.objects.filter(**self.product_filter_set) \
|
||||
.values()[0]
|
||||
|
||||
|
||||
class GuideElementType(models.Model):
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import serializers
|
||||
from rest_framework_recursive.fields import RecursiveField
|
||||
|
||||
from collection import models
|
||||
from establishment.serializers import EstablishmentGuideElementSerializer
|
||||
from location import models as location_models
|
||||
from main.serializers import SiteShortSerializer
|
||||
from utils.serializers import TranslatedField
|
||||
from rest_framework_recursive.fields import RecursiveField
|
||||
from establishment.serializers import EstablishmentGuideElementSerializer
|
||||
from product.serializers import ProductGuideElementSerializer
|
||||
from django.shortcuts import get_object_or_404
|
||||
from utils import exceptions
|
||||
from utils.serializers import TranslatedField
|
||||
|
||||
|
||||
class CollectionBaseSerializer(serializers.ModelSerializer):
|
||||
|
|
@ -53,18 +53,6 @@ class CollectionSerializer(CollectionBaseSerializer):
|
|||
]
|
||||
|
||||
|
||||
class GuideTypeBaseSerializer(serializers.ModelSerializer):
|
||||
"""GuideType serializer."""
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = models.GuideType
|
||||
fields = [
|
||||
'id',
|
||||
'name',
|
||||
]
|
||||
|
||||
|
||||
class GuideFilterBaseSerialzer(serializers.ModelSerializer):
|
||||
"""Serializer for model GuideFilter."""
|
||||
|
||||
|
|
@ -89,8 +77,7 @@ class GuideBaseSerializer(serializers.ModelSerializer):
|
|||
"""Guide serializer"""
|
||||
state_display = serializers.CharField(source='get_state_display',
|
||||
read_only=True)
|
||||
guide_type_detail = GuideTypeBaseSerializer(read_only=True,
|
||||
source='guide_type')
|
||||
guide_type_display = serializers.CharField(read_only=True)
|
||||
site_detail = SiteShortSerializer(read_only=True,
|
||||
source='site')
|
||||
guide_filters = GuideFilterBaseSerialzer(read_only=True,
|
||||
|
|
@ -112,7 +99,7 @@ class GuideBaseSerializer(serializers.ModelSerializer):
|
|||
'vintage',
|
||||
'slug',
|
||||
'guide_type',
|
||||
'guide_type_detail',
|
||||
'guide_type_display',
|
||||
'site',
|
||||
'site_detail',
|
||||
'state',
|
||||
|
|
@ -128,8 +115,9 @@ class GuideBaseSerializer(serializers.ModelSerializer):
|
|||
'site': {'write_only': True},
|
||||
'state': {'write_only': True},
|
||||
'start': {'required': True},
|
||||
'slug': {'required': True},
|
||||
'count_objects_during_init': {'read_only': True}
|
||||
'slug': {'required': False},
|
||||
'count_objects_during_init': {'read_only': True},
|
||||
'vintage': {'required': True},
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -155,7 +143,7 @@ class GuideFilterBaseSerializer(serializers.ModelSerializer):
|
|||
'guide',
|
||||
]
|
||||
extra_kwargs = {
|
||||
'guide': {'write_only': True}
|
||||
'guide': {'write_only': True, 'required': False},
|
||||
}
|
||||
|
||||
@property
|
||||
|
|
@ -168,8 +156,9 @@ class GuideFilterBaseSerializer(serializers.ModelSerializer):
|
|||
guide = get_object_or_404(models.Guide.objects.all(),
|
||||
pk=self.request_kwargs.get('pk'))
|
||||
validated_data['guide'] = guide
|
||||
|
||||
return super().create(validated_data)
|
||||
guide_filter = super().create(validated_data)
|
||||
guide.generate_elements()
|
||||
return guide_filter
|
||||
|
||||
|
||||
class GuideElementBaseSerializer(serializers.ModelSerializer):
|
||||
|
|
@ -230,7 +219,7 @@ class AdvertorialBaseSerializer(serializers.ModelSerializer):
|
|||
guide = get_object_or_404(models.Guide.objects.all(),
|
||||
pk=self.request_kwargs.get('pk'))
|
||||
root_node = models.GuideElement.objects.get_root_node(guide)
|
||||
guide_element_qs = root_node.get_children().filter(pk=self.request_kwargs.get('element_pk'))
|
||||
guide_element_qs = root_node.get_descendants().filter(pk=self.request_kwargs.get('element_pk'))
|
||||
guide_element = guide_element_qs.first()
|
||||
|
||||
if not guide_element_qs.exists():
|
||||
|
|
|
|||
|
|
@ -71,8 +71,6 @@ def generate_establishment_guide_elements(guide_id: int, queryset_values: dict,
|
|||
f'DETAIL: Guide ID {guide_id} - {e}')
|
||||
else:
|
||||
guide.update_count_related_objects()
|
||||
# Update tree indexes
|
||||
GuideElement._tree_manager.rebuild()
|
||||
|
||||
|
||||
@shared_task
|
||||
|
|
@ -129,5 +127,3 @@ def generate_product_guide_elements(guide_id: int, queryset_values: dict):
|
|||
f'DETAIL: Guide ID {guide_id} - {e}')
|
||||
else:
|
||||
guide.update_count_related_objects()
|
||||
# Update tree indexes
|
||||
GuideElement._tree_manager.rebuild()
|
||||
|
|
|
|||
|
|
@ -14,8 +14,14 @@ urlpatterns = [
|
|||
name='guide-list-create'),
|
||||
path('guides/<int:pk>/', views.GuideElementListView.as_view(),
|
||||
name='guide-element-list'),
|
||||
path('guides/<int:pk>/element/<int:element_pk>/advertorial/', views.AdvertorialCreateDestroyView.as_view(),
|
||||
name='guide-advertorial-create-destroy'),
|
||||
path('guides/<int:pk>/regenerate/', views.GuideUpdateView.as_view(),
|
||||
name='guide-regenerate'),
|
||||
path('guides/<int:pk>/element/<int:element_pk>/advertorial/',
|
||||
views.AdvertorialCreateView.as_view(),
|
||||
name='guide-advertorial-create'),
|
||||
path('guides/<int:pk>/element/<int:element_pk>/advertorial/<int:advertorial_pk>/',
|
||||
views.AdvertorialDestroyView.as_view(),
|
||||
name='guide-advertorial-destroy'),
|
||||
path('guides/<int:pk>/filters/', views.GuideFilterCreateView.as_view(),
|
||||
name='guide-filter-list-create'),
|
||||
] + router.urls
|
||||
|
|
|
|||
|
|
@ -36,7 +36,8 @@ class GuideBaseView(generics.GenericAPIView):
|
|||
.annotate_restaurant_counter() \
|
||||
.annotate_shop_counter() \
|
||||
.annotate_wine_counter() \
|
||||
.annotate_present_objects_counter()
|
||||
.annotate_present_objects_counter() \
|
||||
.distinct()
|
||||
|
||||
|
||||
class GuideFilterBaseView(generics.GenericAPIView):
|
||||
|
|
@ -131,7 +132,32 @@ class GuideElementListView(GuideElementBaseView,
|
|||
return models.GuideElement.objects.none()
|
||||
|
||||
|
||||
class AdvertorialCreateDestroyView(AdvertorialBaseView,
|
||||
generics.CreateAPIView,
|
||||
generics.DestroyAPIView):
|
||||
class GuideUpdateView(GuideBaseView):
|
||||
"""View for model GuideElement for back office users."""
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""POST-method to regenerate elements of guide instance."""
|
||||
guide = get_object_or_404(models.Guide.objects.all(),
|
||||
pk=self.kwargs.get('pk'))
|
||||
guide.regenerate_elements()
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class AdvertorialCreateView(AdvertorialBaseView,
|
||||
generics.CreateAPIView):
|
||||
"""View for model Advertorial for back office users."""
|
||||
|
||||
def post(self, request, *args, **kwargs):
|
||||
"""Overridden post method."""
|
||||
super(AdvertorialCreateView, self).create(request, *args, **kwargs)
|
||||
return Response(status=status.HTTP_200_OK)
|
||||
|
||||
|
||||
class AdvertorialDestroyView(AdvertorialBaseView,
|
||||
generics.DestroyAPIView):
|
||||
"""View for model Advertorial for back office users."""
|
||||
lookup_url_kwarg = 'advertorial_pk'
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
"""Overridden delete method."""
|
||||
return self.destroy(request, *args, **kwargs)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,6 @@ from django.utils.translation import gettext_lazy as _
|
|||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
from timezone_field import TimeZoneField
|
||||
|
||||
from collection.models import Collection
|
||||
from location.models import Address
|
||||
from location.models import WineOriginAddressMixin
|
||||
from main.models import Award, Currency
|
||||
|
|
@ -200,6 +199,8 @@ class EstablishmentQuerySet(models.QuerySet):
|
|||
If establishments in collection POP and its mark is null, then
|
||||
intermediate_mark is set to 10;
|
||||
"""
|
||||
from collection.models import Collection
|
||||
|
||||
return self.annotate(intermediate_public_mark=Case(
|
||||
When(
|
||||
collections__collection_type=Collection.POP,
|
||||
|
|
|
|||
|
|
@ -61,8 +61,11 @@ class GuideSerializer(TransferSerializerMixin):
|
|||
return qs.first()
|
||||
|
||||
def get_guide_type(self, inserter_field):
|
||||
guide_type, _ = models.GuideType.objects.get_or_create(name=inserter_field)
|
||||
return guide_type
|
||||
if inserter_field:
|
||||
if inserter_field.startswith('restaurant'):
|
||||
return models.Guide.RESTAURANT
|
||||
elif inserter_field.startswith('wine'):
|
||||
return models.Guide.WINE
|
||||
|
||||
|
||||
class GuideFilterSerializer(TransferSerializerMixin):
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user