Merge branch 'develop' into feature/establishment-gallery
# Conflicts: # apps/product/serializers/common.py
This commit is contained in:
commit
dce951c4f9
17
apps/advertisement/migrations/0008_auto_20191116_1135.py
Normal file
17
apps/advertisement/migrations/0008_auto_20191116_1135.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 2.2.7 on 2019-11-16 11:35
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('advertisement', '0007_auto_20191115_0750'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='advertisement',
|
||||
options={'verbose_name': 'Advertisement', 'verbose_name_plural': 'Advertisements'},
|
||||
),
|
||||
]
|
||||
|
|
@ -13,10 +13,50 @@ from utils.methods import get_user_ip
|
|||
class CheckWhetherBookingAvailable(generics.GenericAPIView):
|
||||
""" Checks which service to use if establishmend is managed by any """
|
||||
|
||||
_VALID_GUESTONLINE_PERIODS = {'lunch', 'dinner', 'afternoon', 'breakfast'}
|
||||
_GUESTONLINE_PERIODS_TO_PRIOR = {
|
||||
'breakfast': 1,
|
||||
'lunch': 2,
|
||||
'afternoon': 3,
|
||||
'dinner': 4,
|
||||
}
|
||||
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
serializer_class = CheckBookingSerializer
|
||||
pagination_class = None
|
||||
|
||||
def _fill_period_template(self, period_template, period_name):
|
||||
period_template_copy = period_template.copy()
|
||||
period_template_copy['period'] = period_name
|
||||
return period_template_copy
|
||||
|
||||
def _preprocess_guestonline_response(self, response):
|
||||
periods = response['periods']
|
||||
periods_by_name = {period['period']: period for period in periods if 'period' in period}
|
||||
if not periods_by_name:
|
||||
raise ValueError('Empty guestonline response')
|
||||
|
||||
period_template = iter(periods_by_name.values()).__next__().copy()
|
||||
period_template.pop('total_left_seats')
|
||||
period_template['hours'] = []
|
||||
period_template.pop('period')
|
||||
|
||||
processed_periods = [
|
||||
periods_by_name[period_name]
|
||||
if period_name in periods_by_name
|
||||
else self._fill_period_template(period_template, period_name)
|
||||
for period_name in CheckWhetherBookingAvailable._VALID_GUESTONLINE_PERIODS
|
||||
]
|
||||
|
||||
unnamed_periods = filter(lambda period: 'period' not in period, periods)
|
||||
for unnamed_period in unnamed_periods:
|
||||
processed_periods.append(unnamed_period)
|
||||
|
||||
response['periods'] = sorted(processed_periods,
|
||||
key=lambda x: self._GUESTONLINE_PERIODS_TO_PRIOR[x.get('period', 'lunch')])
|
||||
|
||||
return response
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
is_booking_available = False
|
||||
establishment = get_object_or_404(Establishment, pk=kwargs['establishment_id'])
|
||||
|
|
@ -24,12 +64,12 @@ class CheckWhetherBookingAvailable(generics.GenericAPIView):
|
|||
date = request.query_params.get('date')
|
||||
g_service = GuestonlineService()
|
||||
l_service = LastableService()
|
||||
if (not establishment.lastable_id is None) and l_service \
|
||||
if establishment.lastable_id is not None and l_service \
|
||||
.check_whether_booking_available(establishment.lastable_id, date):
|
||||
is_booking_available = True
|
||||
service = l_service
|
||||
service.service_id = establishment.lastable_id
|
||||
elif (not establishment.guestonline_id is None) and g_service \
|
||||
elif establishment.guestonline_id is not None and g_service \
|
||||
.check_whether_booking_available(establishment.guestonline_id,
|
||||
**g_service.get_certain_keys(request.query_params,
|
||||
{'date', 'persons'})):
|
||||
|
|
@ -41,7 +81,11 @@ class CheckWhetherBookingAvailable(generics.GenericAPIView):
|
|||
'available': is_booking_available,
|
||||
'type': service.service if service else None,
|
||||
}
|
||||
response.update({'details': service.response} if service and service.response else {})
|
||||
|
||||
service_response = self._preprocess_guestonline_response(service.response) \
|
||||
if establishment.guestonline_id is not None \
|
||||
else service.response
|
||||
response.update({'details': service_response} if service and service.response else {})
|
||||
return Response(data=response, status=200)
|
||||
|
||||
|
||||
|
|
@ -97,8 +141,9 @@ class UpdatePendingBooking(generics.UpdateAPIView):
|
|||
r = service.update_booking(service.get_certain_keys(data, {
|
||||
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id', 'note',
|
||||
}, {
|
||||
'email', 'phone', 'last_name', 'first_name', 'country_code', 'pending_booking_id',
|
||||
}))
|
||||
'email', 'phone', 'last_name', 'first_name',
|
||||
'country_code', 'pending_booking_id',
|
||||
}))
|
||||
if isinstance(r, Response):
|
||||
return r
|
||||
if data.get('newsletter'):
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
from django.shortcuts import get_object_or_404
|
||||
from rest_framework import generics
|
||||
from rest_framework import permissions
|
||||
|
||||
from collection import models
|
||||
from utils.pagination import ProjectPageNumberPagination
|
||||
from django.shortcuts import get_object_or_404
|
||||
from establishment.serializers import EstablishmentBaseSerializer
|
||||
from collection.serializers import common as serializers
|
||||
from establishment.serializers import EstablishmentSimilarSerializer
|
||||
from utils.pagination import ProjectPageNumberPagination
|
||||
|
||||
|
||||
# Mixins
|
||||
|
|
@ -53,7 +53,7 @@ class CollectionEstablishmentListView(CollectionListView):
|
|||
"""Retrieve list of establishment for collection."""
|
||||
lookup_field = 'slug'
|
||||
pagination_class = ProjectPageNumberPagination
|
||||
serializer_class = EstablishmentBaseSerializer
|
||||
serializer_class = EstablishmentSimilarSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from rest_framework import serializers
|
|||
from comment import models as comment_models
|
||||
from comment.serializers import common as comment_serializers
|
||||
from establishment import models
|
||||
from location.serializers import AddressBaseSerializer, CitySerializer, AddressDetailSerializer
|
||||
from location.serializers import AddressBaseSerializer, CitySerializer, AddressDetailSerializer, CityShortSerializer
|
||||
from main.serializers import AwardSerializer, CurrencySerializer
|
||||
from tag.serializers import TagBaseSerializer
|
||||
from timetable.serialziers import ScheduleRUDSerializer
|
||||
|
|
@ -18,6 +18,7 @@ from utils.serializers import ImageBaseSerializer
|
|||
|
||||
class ContactPhonesSerializer(serializers.ModelSerializer):
|
||||
"""Contact phone serializer"""
|
||||
|
||||
class Meta:
|
||||
model = models.ContactPhone
|
||||
fields = [
|
||||
|
|
@ -27,6 +28,7 @@ class ContactPhonesSerializer(serializers.ModelSerializer):
|
|||
|
||||
class ContactEmailsSerializer(serializers.ModelSerializer):
|
||||
"""Contact email serializer"""
|
||||
|
||||
class Meta:
|
||||
model = models.ContactEmail
|
||||
fields = [
|
||||
|
|
@ -36,6 +38,7 @@ class ContactEmailsSerializer(serializers.ModelSerializer):
|
|||
|
||||
class SocialNetworkRelatedSerializers(serializers.ModelSerializer):
|
||||
"""Social network serializers."""
|
||||
|
||||
class Meta:
|
||||
model = models.SocialNetwork
|
||||
fields = [
|
||||
|
|
@ -46,7 +49,6 @@ class SocialNetworkRelatedSerializers(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class PlateSerializer(ProjectModelSerializer):
|
||||
|
||||
name_translated = TranslatedField()
|
||||
currency = CurrencySerializer(read_only=True)
|
||||
|
||||
|
|
@ -192,6 +194,28 @@ class EstablishmentShortSerializer(serializers.ModelSerializer):
|
|||
]
|
||||
|
||||
|
||||
class EstablishmentProductShortSerializer(serializers.ModelSerializer):
|
||||
"""SHORT Serializer for displaying info about an establishment on product page."""
|
||||
establishment_type = EstablishmentTypeGeoSerializer()
|
||||
establishment_subtypes = EstablishmentSubTypeBaseSerializer(many=True)
|
||||
address = AddressBaseSerializer()
|
||||
city = CityShortSerializer(source='address.city', allow_null=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
model = models.Establishment
|
||||
fields = [
|
||||
'id',
|
||||
'name',
|
||||
'index_name',
|
||||
'slug',
|
||||
'city',
|
||||
'establishment_type',
|
||||
'establishment_subtypes',
|
||||
'address',
|
||||
]
|
||||
|
||||
|
||||
class EstablishmentProductSerializer(EstablishmentShortSerializer):
|
||||
"""Serializer for displaying info about an establishment on product page."""
|
||||
|
||||
|
|
@ -325,6 +349,12 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
|
|||
]
|
||||
|
||||
|
||||
class EstablishmentSimilarSerializer(EstablishmentBaseSerializer):
|
||||
"""Serializer for Establishment model."""
|
||||
|
||||
address = AddressDetailSerializer(read_only=True)
|
||||
|
||||
|
||||
class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer):
|
||||
"""Create comment serializer"""
|
||||
mark = serializers.IntegerField()
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class EstablishmentRecentReviewListView(EstablishmentListView):
|
|||
class EstablishmentSimilarListView(EstablishmentListView):
|
||||
"""Resource for getting a list of establishments."""
|
||||
|
||||
serializer_class = serializers.EstablishmentBaseSerializer
|
||||
serializer_class = serializers.EstablishmentSimilarSerializer
|
||||
pagination_class = EstablishmentPortionPagination
|
||||
|
||||
def get_queryset(self):
|
||||
|
|
|
|||
|
|
@ -54,6 +54,20 @@ class RegionSerializer(serializers.ModelSerializer):
|
|||
'country_id'
|
||||
]
|
||||
|
||||
class CityShortSerializer(serializers.ModelSerializer):
|
||||
"""Short city serializer"""
|
||||
country = CountrySerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class"""
|
||||
model = models.City
|
||||
fields = (
|
||||
'id',
|
||||
'name',
|
||||
'code',
|
||||
'country',
|
||||
)
|
||||
|
||||
|
||||
class CitySerializer(serializers.ModelSerializer):
|
||||
"""City serializer."""
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
"""Location app views."""
|
||||
from rest_framework import generics
|
||||
from rest_framework import permissions
|
||||
|
||||
from django.db.models.expressions import RawSQL
|
||||
from location import models, serializers
|
||||
from utils.models import get_current_locale
|
||||
|
||||
|
||||
# Mixins
|
||||
|
|
@ -37,7 +38,9 @@ class CountryListView(CountryViewMixin, generics.ListAPIView):
|
|||
"""List view for model Country."""
|
||||
|
||||
pagination_class = None
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset().order_by(RawSQL("name->>%s", (get_current_locale(),)))
|
||||
return qs
|
||||
|
||||
class CountryRetrieveView(CountryViewMixin, generics.RetrieveAPIView):
|
||||
"""Retrieve view for model Country."""
|
||||
|
|
|
|||
20
apps/notification/migrations/0003_auto_20191116_1248.py
Normal file
20
apps/notification/migrations/0003_auto_20191116_1248.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# Generated by Django 2.2.7 on 2019-11-16 12:48
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('notification', '0002_subscriber_old_id'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='subscriber',
|
||||
name='user',
|
||||
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='subscriber', to=settings.AUTH_USER_MODEL, verbose_name='User'),
|
||||
),
|
||||
]
|
||||
|
|
@ -74,7 +74,7 @@ class Subscriber(ProjectBaseMixin):
|
|||
(USABLE, _('Usable')),
|
||||
)
|
||||
|
||||
user = models.OneToOneField(
|
||||
user = models.ForeignKey(
|
||||
User,
|
||||
blank=True,
|
||||
null=True,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,5 @@
|
|||
from pprint import pprint
|
||||
|
||||
from django.db.models import Count
|
||||
|
||||
from transfer.models import EmailAddresses, NewsletterSubscriber
|
||||
from transfer.serializers.notification import SubscriberSerializer, NewsletterSubscriberSerializer
|
||||
|
||||
|
|
@ -25,14 +23,14 @@ def transfer_newsletter_subscriber():
|
|||
'email_address__ip',
|
||||
'email_address__country_code',
|
||||
'email_address__locale',
|
||||
'created_at',
|
||||
'updated_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), many=True)
|
||||
if serialized_data.is_valid():
|
||||
serialized_data.save()
|
||||
else:
|
||||
pprint(f'NewsletterSubscriber serializer errors: {serialized_data.errors}')
|
||||
|
||||
|
||||
data_types = {
|
||||
|
|
|
|||
|
|
@ -83,7 +83,12 @@ class ProductQuerySet(models.QuerySet):
|
|||
def with_extended_related(self):
|
||||
"""Returns qs with almost all related objects."""
|
||||
return self.with_base_related() \
|
||||
.prefetch_related('tags', 'standards', 'classifications', 'classifications__standard',
|
||||
.prefetch_related('tags', 'tags__category', 'tags__category__country',
|
||||
'standards', 'classifications', 'classifications__standard',
|
||||
'establishment__address', 'establishment__establishment_type',
|
||||
'establishment__address__city', 'establishment__address__city__country',
|
||||
'establishment__establishment_subtypes', 'product_gallery',
|
||||
'gallery', 'product_type', 'subtypes',
|
||||
'classifications__classification_type', 'classifications__tags') \
|
||||
.select_related('wine_region', 'wine_sub_region')
|
||||
|
||||
|
|
@ -247,15 +252,14 @@ class Product(GalleryModelMixin, TranslatedFieldsMixin, BaseAttributes):
|
|||
|
||||
@property
|
||||
def related_tags(self):
|
||||
return self.tags.exclude(
|
||||
category__index_name__in=['sugar-content', 'wine-color', 'bottles-produced',
|
||||
'serial-number', 'grape-variety'])
|
||||
return self.tags.exclude(category__index_name__in=['sugar-content', 'wine-color', 'bottles-produced',
|
||||
'serial-number', 'grape-variety']).prefetch_related('category')
|
||||
|
||||
@property
|
||||
def display_name(self):
|
||||
name = f'{self.name} ' \
|
||||
f'({self.vintage if self.vintage else "BSA"})'
|
||||
if self.establishment.name:
|
||||
if self.establishment and self.establishment.name:
|
||||
name = f'{self.establishment.name} - ' + name
|
||||
return name
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from rest_framework import serializers
|
|||
|
||||
from comment.models import Comment
|
||||
from comment.serializers import CommentSerializer
|
||||
from establishment.serializers import EstablishmentShortSerializer, EstablishmentProductSerializer
|
||||
from establishment.serializers import EstablishmentShortSerializer, EstablishmentProductSerializer, EstablishmentProductShortSerializer
|
||||
from gallery.models import Image
|
||||
from product import models
|
||||
from review.serializers import ReviewShortSerializer
|
||||
|
|
@ -12,13 +12,13 @@ from utils import exceptions as utils_exceptions
|
|||
from utils.serializers import TranslatedField, FavoritesCreateSerializer, ImageBaseSerializer
|
||||
from main.serializers import AwardSerializer
|
||||
from location.serializers import WineRegionBaseSerializer, WineSubRegionBaseSerializer
|
||||
from tag.serializers import TagBaseSerializer, TagCategoryShortSerializer
|
||||
from tag.serializers import TagBaseSerializer, TagCategoryProductSerializer
|
||||
|
||||
|
||||
class ProductTagSerializer(TagBaseSerializer):
|
||||
"""Serializer for model Tag."""
|
||||
|
||||
category = TagCategoryShortSerializer(read_only=True)
|
||||
category = TagCategoryProductSerializer(read_only=True)
|
||||
|
||||
class Meta(TagBaseSerializer.Meta):
|
||||
"""Meta class."""
|
||||
|
|
@ -83,21 +83,12 @@ class ProductStandardBaseSerializer(serializers.ModelSerializer):
|
|||
)
|
||||
|
||||
|
||||
class ProductCropImageSerializer(serializers.Serializer):
|
||||
"""Serializer for product image."""
|
||||
|
||||
|
||||
class ProductImageSerializer(ImageBaseSerializer):
|
||||
"""Serializer for product image."""
|
||||
auto_crop_images = ProductCropImageSerializer(allow_null=True)
|
||||
|
||||
|
||||
class ProductBaseSerializer(serializers.ModelSerializer):
|
||||
"""Product base serializer."""
|
||||
name = serializers.CharField(source='display_name', read_only=True)
|
||||
product_type = ProductTypeBaseSerializer(read_only=True)
|
||||
subtypes = ProductSubTypeBaseSerializer(many=True, read_only=True)
|
||||
establishment_detail = EstablishmentShortSerializer(source='establishment', read_only=True)
|
||||
establishment_detail = EstablishmentProductShortSerializer(source='establishment', read_only=True)
|
||||
tags = ProductTagSerializer(source='related_tags', many=True, read_only=True)
|
||||
wine_region = WineRegionBaseSerializer(read_only=True)
|
||||
wine_colors = TagBaseSerializer(many=True, read_only=True)
|
||||
|
|
@ -128,6 +119,7 @@ class ProductBaseSerializer(serializers.ModelSerializer):
|
|||
class ProductDetailSerializer(ProductBaseSerializer):
|
||||
"""Product detail serializer."""
|
||||
description_translated = TranslatedField()
|
||||
establishment_detail = EstablishmentShortSerializer(source='establishment', read_only=True)
|
||||
review = ReviewShortSerializer(source='last_published_review', read_only=True)
|
||||
awards = AwardSerializer(many=True, read_only=True)
|
||||
classifications = ProductClassificationBaseSerializer(many=True, read_only=True)
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ class ProductListView(ProductBaseView, generics.ListAPIView):
|
|||
serializer_class = serializers.ProductBaseSerializer
|
||||
filter_class = filters.ProductFilterSet
|
||||
|
||||
def get_queryset(self):
|
||||
qs = super().get_queryset().with_extended_related()
|
||||
return qs
|
||||
|
||||
|
||||
class ProductDetailView(ProductBaseView, generics.RetrieveAPIView):
|
||||
"""Detail view fro model Product."""
|
||||
|
|
|
|||
|
|
@ -95,13 +95,15 @@ class ProductDocument(Document):
|
|||
},
|
||||
multi=True
|
||||
)
|
||||
name = fields.TextField(attr='display_name', analyzer='english')
|
||||
name_ru = fields.TextField(attr='display_name', analyzer='russian')
|
||||
name_fr = fields.TextField(attr='display_name', analyzer='french')
|
||||
|
||||
class Django:
|
||||
model = models.Product
|
||||
fields = (
|
||||
'id',
|
||||
'category',
|
||||
'name',
|
||||
'available',
|
||||
'public_mark',
|
||||
'slug',
|
||||
|
|
|
|||
|
|
@ -39,7 +39,8 @@ class ProductSubtypeDocumentSerializer(serializers.Serializer):
|
|||
id = serializers.IntegerField()
|
||||
name_translated = serializers.SerializerMethodField()
|
||||
|
||||
get_name_translated = lambda obj: get_translated_value(obj.name)
|
||||
def get_name_translated(self, obj):
|
||||
return get_translated_value(obj.name)
|
||||
|
||||
|
||||
class WineRegionCountryDocumentSerialzer(serializers.Serializer):
|
||||
|
|
@ -64,6 +65,9 @@ class WineRegionDocumentSerializer(serializers.Serializer):
|
|||
name = serializers.CharField()
|
||||
country = WineRegionCountryDocumentSerialzer(allow_null=True)
|
||||
|
||||
def get_attribute(self, instance):
|
||||
return instance.wine_region if instance and instance.wine_region else None
|
||||
|
||||
|
||||
class WineColorDocumentSerializer(serializers.Serializer):
|
||||
"""Wine color ES document serializer,"""
|
||||
|
|
@ -79,6 +83,18 @@ class WineColorDocumentSerializer(serializers.Serializer):
|
|||
return get_translated_value(obj.label)
|
||||
|
||||
|
||||
class ProductTypeDocumentSerializer(serializers.Serializer):
|
||||
"""Product type ES document serializer."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
index_name = serializers.CharField()
|
||||
name_translated = serializers.SerializerMethodField()
|
||||
|
||||
@staticmethod
|
||||
def get_name_translated(obj):
|
||||
return get_translated_value(obj.name)
|
||||
|
||||
|
||||
class ProductEstablishmentDocumentSerializer(serializers.Serializer):
|
||||
"""Related to Product Establishment ES document serializer."""
|
||||
|
||||
|
|
@ -199,16 +215,12 @@ class ProductDocumentSerializer(DocumentSerializer):
|
|||
"""Product document serializer"""
|
||||
|
||||
tags = TagsDocumentSerializer(many=True)
|
||||
subtypes = ProductSubtypeDocumentSerializer(many=True)
|
||||
subtypes = ProductSubtypeDocumentSerializer(many=True, allow_null=True)
|
||||
wine_region = WineRegionDocumentSerializer(allow_null=True)
|
||||
wine_colors = WineColorDocumentSerializer(many=True)
|
||||
product_type = serializers.SerializerMethodField()
|
||||
product_type = ProductTypeDocumentSerializer(allow_null=True)
|
||||
establishment_detail = ProductEstablishmentDocumentSerializer(source='establishment', allow_null=True)
|
||||
|
||||
@staticmethod
|
||||
def get_product_type(obj):
|
||||
return get_translated_value(obj.product_type.name if obj.product_type else {})
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
|
|
|
|||
|
|
@ -91,8 +91,6 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
|
|||
'boost': 4},
|
||||
'transliterated_name': {'fuzziness': 'auto:2,5',
|
||||
'boost': 3},
|
||||
'index_name': {'fuzziness': 'auto:2,5',
|
||||
'boost': 2},
|
||||
'description': {'fuzziness': 'auto:2,5'},
|
||||
}
|
||||
translated_search_fields = (
|
||||
|
|
@ -199,7 +197,7 @@ class ProductDocumentViewSet(BaseDocumentViewSet):
|
|||
"""Product document ViewSet."""
|
||||
|
||||
document = ProductDocument
|
||||
lookup_field = 'slug'
|
||||
# lookup_field = 'slug'
|
||||
pagination_class = ProjectMobilePagination
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
serializer_class = serializers.ProductDocumentSerializer
|
||||
|
|
@ -212,19 +210,22 @@ class ProductDocumentViewSet(BaseDocumentViewSet):
|
|||
filter_backends = [
|
||||
FilteringFilterBackend,
|
||||
filters.CustomSearchFilterBackend,
|
||||
GeoSpatialFilteringFilterBackend,
|
||||
DefaultOrderingFilterBackend,
|
||||
# GeoSpatialFilteringFilterBackend,
|
||||
# DefaultOrderingFilterBackend,
|
||||
]
|
||||
|
||||
search_fields = {
|
||||
'name': {'fuzziness': 'auto:2,5',
|
||||
'boost': 4},
|
||||
'boost': 8},
|
||||
'name_ru': {'fuzziness': 'auto:2,5',
|
||||
'boost': 6},
|
||||
'name_fr': {'fuzziness': 'auto:2,5',
|
||||
'boost': 7},
|
||||
'transliterated_name': {'fuzziness': 'auto:2,5',
|
||||
'boost': 3},
|
||||
'index_name': {'fuzziness': 'auto:2,5',
|
||||
'boost': 2},
|
||||
'description': {'fuzziness': 'auto:2,5'},
|
||||
}
|
||||
|
||||
translated_search_fields = (
|
||||
'description',
|
||||
)
|
||||
|
|
@ -248,7 +249,7 @@ class ProductDocumentViewSet(BaseDocumentViewSet):
|
|||
'for_establishment': {
|
||||
'field': 'establishment.slug',
|
||||
},
|
||||
'type': {
|
||||
'product_type': {
|
||||
'field': 'product_type.index_name',
|
||||
},
|
||||
'subtype': {
|
||||
|
|
@ -259,5 +260,5 @@ class ProductDocumentViewSet(BaseDocumentViewSet):
|
|||
]
|
||||
}
|
||||
}
|
||||
geo_spatial_filter_fields = {
|
||||
}
|
||||
# geo_spatial_filter_fields = {
|
||||
# }
|
||||
|
|
@ -31,13 +31,18 @@ class TagCategoryFilterSet(TagsBaseFilterSet):
|
|||
"""TagCategory filterset."""
|
||||
|
||||
establishment_type = filters.CharFilter(method='by_establishment_type')
|
||||
product_type = filters.CharFilter(method='by_product_type')
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.TagCategory
|
||||
fields = ('type',
|
||||
'establishment_type', )
|
||||
'establishment_type',
|
||||
'product_type', )
|
||||
|
||||
def by_product_type(self, queryset, name, value):
|
||||
return queryset.by_product_type(value)
|
||||
|
||||
# todo: filter by establishment type
|
||||
def by_establishment_type(self, queryset, name, value):
|
||||
|
|
|
|||
|
|
@ -3,87 +3,116 @@ from django.core.management.base import BaseCommand
|
|||
from establishment.models import Establishment, EstablishmentType
|
||||
from transfer import models as legacy
|
||||
from tag.models import Tag, TagCategory
|
||||
from tqdm import tqdm
|
||||
from django.db import connections
|
||||
from collections import namedtuple
|
||||
|
||||
|
||||
def namedtuplefetchall(cursor):
|
||||
"Return all rows from a cursor as a namedtuple"
|
||||
desc = cursor.description
|
||||
nt_result = namedtuple('Result', [col[0] for col in desc])
|
||||
return [nt_result(*row) for row in cursor.fetchall()]
|
||||
|
||||
|
||||
def metadata_category_sql():
|
||||
with connections['legacy'].cursor() as cursor:
|
||||
cursor.execute(
|
||||
'''SELECT
|
||||
`key`,
|
||||
establishments.type,
|
||||
key_value_metadata.`value_type`,
|
||||
public,
|
||||
key_value_metadata.id as 'old_id'
|
||||
FROM metadata
|
||||
LEFT JOIN establishments
|
||||
ON metadata.establishment_id=establishments.id
|
||||
LEFT JOIN key_value_metadata
|
||||
ON metadata.key=key_value_metadata.key_name
|
||||
GROUP BY
|
||||
establishments.type,
|
||||
`key`,
|
||||
key_value_metadata.`value_type`,
|
||||
public, old_id;'''
|
||||
)
|
||||
return namedtuplefetchall(cursor)
|
||||
|
||||
|
||||
def metadata_tags_sql():
|
||||
with connections['legacy'].cursor() as cursor:
|
||||
cursor.execute(
|
||||
"""
|
||||
SELECT
|
||||
value,
|
||||
`key` as category,
|
||||
establishment_id
|
||||
FROM metadata
|
||||
WHERE establishment_id is not null"""
|
||||
)
|
||||
return namedtuplefetchall(cursor)
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Add tags values from old db to new db'
|
||||
|
||||
def get_type(self, meta):
|
||||
meta_type = meta.value_type
|
||||
if not meta.value_type:
|
||||
if meta.key == 'wineyard_visits':
|
||||
meta_type = 'list'
|
||||
elif meta.key in ['private_room', 'outside_sits']:
|
||||
meta_type = 'bool'
|
||||
return meta_type
|
||||
|
||||
def get_label(self, text):
|
||||
sp = text.split('_')
|
||||
label = ' '.join([sp[0].capitalize()] + sp[1:])
|
||||
return label
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
|
||||
existing_establishment = Establishment.objects.filter(
|
||||
old_id__isnull=False, tags__isnull=True
|
||||
old_id__isnull=False
|
||||
)
|
||||
ESTABLISHMENT = 1
|
||||
SHOP = 2
|
||||
RESTAURANT = 3
|
||||
WINEYARD = 4
|
||||
|
||||
MAPPER = {
|
||||
RESTAURANT: EstablishmentType.RESTAURANT,
|
||||
WINEYARD: EstablishmentType.PRODUCER,
|
||||
SHOP: EstablishmentType.ARTISAN
|
||||
'Restaurant': EstablishmentType.RESTAURANT,
|
||||
'Wineyard': EstablishmentType.PRODUCER,
|
||||
'Shop': EstablishmentType.ARTISAN
|
||||
}
|
||||
# remove old black category
|
||||
for establishment_tag in tqdm(EstablishmentType.objects.all()):
|
||||
establishment_tag.tag_categories.remove(*list(
|
||||
establishment_tag.tag_categories.exclude(
|
||||
tags__establishments__isnull=False).distinct()))
|
||||
|
||||
mapper_values_meta = legacy.KeyValueMetadatumKeyValueMetadatumEstablishments.objects.all()
|
||||
for key, value in MAPPER.items():
|
||||
values_meta_id_list = mapper_values_meta.filter(
|
||||
key_value_metadatum_establishment_id=key
|
||||
).values_list('key_value_metadatum_id')
|
||||
# created Tag Category
|
||||
for meta in tqdm(metadata_category_sql()):
|
||||
category, _ = TagCategory.objects.update_or_create(
|
||||
index_name=meta.key,
|
||||
defaults={
|
||||
"public": True if meta.public == 1 else False,
|
||||
"value_type": self.get_type(meta),
|
||||
"label": {"en-GB": self.get_label(meta.key)}
|
||||
}
|
||||
)
|
||||
|
||||
est_type, _ = EstablishmentType.objects.get_or_create(index_name=value)
|
||||
# add to EstablishmentType
|
||||
est_type = EstablishmentType.objects.get(index_name=MAPPER[meta.type])
|
||||
if category not in est_type.tag_categories.all():
|
||||
est_type.tag_categories.add(category)
|
||||
|
||||
key_value_metadata = legacy.KeyValueMetadata.objects.filter(
|
||||
id__in=values_meta_id_list)
|
||||
count = 0
|
||||
for meta_tag in tqdm(metadata_tags_sql()):
|
||||
|
||||
# create TagCategory
|
||||
for key_value in key_value_metadata:
|
||||
tag_category, created = TagCategory.objects.get_or_create(
|
||||
index_name=key_value.key_name,
|
||||
)
|
||||
|
||||
if created:
|
||||
tag_category.label = {
|
||||
'en-GB': key_value.key_name,
|
||||
'fr-FR': key_value.key_name,
|
||||
'ru-RU': key_value.key_name,
|
||||
}
|
||||
tag_category.value_type = key_value.value_type
|
||||
tag_category.save()
|
||||
est_type.tag_categories.add(
|
||||
tag_category
|
||||
)
|
||||
|
||||
# create Tag
|
||||
for tag in key_value.metadata_set.filter(
|
||||
establishment__id__in=list(
|
||||
existing_establishment.values_list('old_id', flat=True)
|
||||
)):
|
||||
|
||||
new_tag, created = Tag.objects.get_or_create(
|
||||
value=tag.value,
|
||||
category=tag_category,
|
||||
)
|
||||
if created:
|
||||
|
||||
sp = tag.value.split('_')
|
||||
value = ' '.join([sp[0].capitalize()] + sp[1:])
|
||||
|
||||
trans = {
|
||||
'en-GB': value,
|
||||
'fr-FR': value,
|
||||
'ru-RU': value,
|
||||
}
|
||||
|
||||
aliases = legacy.MetadatumAliases.objects.filter(value=tag.value)
|
||||
|
||||
for alias in aliases:
|
||||
trans[alias.locale] = alias.meta_alias
|
||||
|
||||
new_tag.label = trans
|
||||
new_tag.save()
|
||||
|
||||
est = existing_establishment.filter(
|
||||
old_id=tag.establishment_id).first()
|
||||
if est:
|
||||
est.tags.add(new_tag)
|
||||
est.save()
|
||||
tag, _ = Tag.objects.update_or_create(
|
||||
category=TagCategory.objects.get(index_name=meta_tag.category),
|
||||
value=meta_tag.value,
|
||||
defaults={
|
||||
"label": {"en-GB": self.get_label(meta_tag.value)}
|
||||
}
|
||||
)
|
||||
establishment = existing_establishment.filter(old_id=meta_tag.establishment_id).first()
|
||||
if establishment:
|
||||
if tag not in establishment.tags.all():
|
||||
establishment.tags.add(tag)
|
||||
count += 1
|
||||
self.stdout.write(self.style.WARNING(f'Created {count} tags to Establishment'))
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
|
||||
from establishment.models import Establishment, EstablishmentType
|
||||
from tag.models import Tag
|
||||
from transfer import models as legacy
|
||||
from tag.models import Tag, TagCategory
|
||||
from tqdm import tqdm
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Add tags translation from old db to new db'
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
translation = legacy.MetadatumAliases.objects.all()
|
||||
# Humanisation for default values
|
||||
|
||||
@staticmethod
|
||||
def humanisation_tag(self):
|
||||
"""Humanisation for default values."""
|
||||
tags = Tag.objects.all()
|
||||
for tag in tags:
|
||||
for tag in tqdm(tags):
|
||||
value = tag.label
|
||||
for k, v in value.items():
|
||||
if isinstance(v, str) and '_' in v:
|
||||
|
|
@ -22,10 +21,14 @@ class Command(BaseCommand):
|
|||
tag.label[k] = v
|
||||
tag.save()
|
||||
|
||||
for trans in translation:
|
||||
def handle(self, *args, **kwargs):
|
||||
"""Translation for existed tags."""
|
||||
translation = legacy.MetadatumAliases.objects.all()
|
||||
# self.humanisation_tag()
|
||||
for trans in tqdm(translation):
|
||||
tag = Tag.objects.filter(value=trans.value).first()
|
||||
if tag:
|
||||
tag.label.update(
|
||||
{trans.locale: trans.meta_alias}
|
||||
)
|
||||
tag.save()
|
||||
tag.save()
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ class Tag(TranslatedFieldsMixin, models.Model):
|
|||
chosen_tag_settings = models.ManyToManyField(Country, through='ChosenTagSettings')
|
||||
priority = models.PositiveIntegerField(null=True, default=0)
|
||||
|
||||
# It does not make sense since in the old base another structure with duplicates
|
||||
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
|
||||
|
||||
old_id_meta_product = models.PositiveIntegerField(_('old id metadata product'),
|
||||
|
|
@ -100,6 +101,10 @@ class TagCategoryQuerySet(models.QuerySet):
|
|||
"""Filter by establishment type index name."""
|
||||
return self.filter(establishment_types__index_name=index_name)
|
||||
|
||||
def by_product_type(self, index_name):
|
||||
"""Filter by product type index name."""
|
||||
return self.filter(product_types__index_name=index_name)
|
||||
|
||||
def with_tags(self, switcher=True):
|
||||
"""Filter by existing tags."""
|
||||
return self.exclude(tags__isnull=switcher)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,21 @@ class TagBackOfficeSerializer(TagBaseSerializer):
|
|||
'category'
|
||||
)
|
||||
|
||||
class TagCategoryProductSerializer(serializers.ModelSerializer):
|
||||
"""SHORT Serializer for TagCategory"""
|
||||
|
||||
label_translated = TranslatedField()
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
||||
model = models.TagCategory
|
||||
fields = (
|
||||
'id',
|
||||
'label_translated',
|
||||
'index_name',
|
||||
)
|
||||
|
||||
|
||||
class TagCategoryBaseSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for model TagCategory."""
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@ class AdvertisementSerializer(serializers.ModelSerializer):
|
|||
href = serializers.CharField()
|
||||
site_id = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Sites.objects.all())
|
||||
start_at = serializers.DateTimeField(allow_null=True)
|
||||
expire_at = serializers.DateTimeField(allow_null=True)
|
||||
|
||||
class Meta:
|
||||
"""Meta class."""
|
||||
|
|
@ -24,29 +22,27 @@ class AdvertisementSerializer(serializers.ModelSerializer):
|
|||
'id',
|
||||
'href',
|
||||
'site_id',
|
||||
'start_at',
|
||||
'expire_at',
|
||||
]
|
||||
|
||||
def validate(self, data):
|
||||
data.update({
|
||||
'old_id': data.pop('id'),
|
||||
'url': data.pop('href'),
|
||||
'site': self.get_site(data.pop('site_id')),
|
||||
'start': data.pop('start_at', None),
|
||||
'end': data.pop('expire_at', None),
|
||||
'site_settings': self.get_site_settings(data.pop('site_id')),
|
||||
})
|
||||
return data
|
||||
|
||||
def create(self, validated_data):
|
||||
site = validated_data.pop('site')
|
||||
obj, _ = self.Meta.model.objects.get_or_create(validated_data)
|
||||
site = validated_data.pop('site_settings')
|
||||
url = validated_data.get('url')
|
||||
|
||||
obj, _ = self.Meta.model.objects.get_or_create(url=url, defaults=validated_data)
|
||||
|
||||
if site and site not in obj.sites.all():
|
||||
obj.sites.add(site)
|
||||
return obj
|
||||
|
||||
def get_site(self, subdomain):
|
||||
def get_site_settings(self, subdomain):
|
||||
subdomain = subdomain.country_code_2 if isinstance(subdomain, Sites) else subdomain
|
||||
qs = SiteSettings.objects.filter(subdomain=subdomain)
|
||||
if qs.exists():
|
||||
|
|
@ -89,5 +85,5 @@ class AdvertisementImageSerializer(AdvertisementSerializer):
|
|||
image_url = validated_data.get('image_url')
|
||||
|
||||
if advertisement and image_url:
|
||||
Page.objects.get_or_create(advertisement=advertisement, image_url=image_url, source=Page.MOBILE)
|
||||
Page.objects.get_or_create(advertisement=advertisement, image_url=image_url, source=Page.WEB)
|
||||
self.Meta.model.objects.get_or_create(source=Page.MOBILE, **validated_data)
|
||||
self.Meta.model.objects.get_or_create(source=Page.WEB, **validated_data)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
from django.db import IntegrityError
|
||||
from rest_framework import serializers
|
||||
|
||||
from account.models import User
|
||||
|
|
@ -41,10 +42,10 @@ class NewsletterSubscriberSerializer(serializers.Serializer):
|
|||
id = serializers.IntegerField()
|
||||
email_address__email = serializers.CharField()
|
||||
email_address__account_id = serializers.IntegerField(allow_null=True)
|
||||
email_address__ip = serializers.CharField(allow_null=True)
|
||||
email_address__country_code = serializers.CharField(allow_null=True)
|
||||
email_address__locale = serializers.CharField(allow_null=True)
|
||||
created_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S')
|
||||
email_address__ip = serializers.CharField(allow_null=True, allow_blank=True)
|
||||
email_address__country_code = serializers.CharField(allow_null=True, allow_blank=True)
|
||||
email_address__locale = serializers.CharField(allow_null=True, allow_blank=True)
|
||||
updated_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S')
|
||||
|
||||
def validate(self, data):
|
||||
data.update({
|
||||
|
|
@ -53,18 +54,28 @@ class NewsletterSubscriberSerializer(serializers.Serializer):
|
|||
'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'),
|
||||
'created': data.pop('updated_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
|
||||
def create(self, validated_data):
|
||||
try:
|
||||
obj = Subscriber.objects.get(email=validated_data['email'])
|
||||
except Subscriber.DoesNotExist:
|
||||
obj = Subscriber.objects.create(**validated_data)
|
||||
else:
|
||||
current_data = obj.created
|
||||
if validated_data['created'] > current_data:
|
||||
obj.ip_address = validated_data['ip_address']
|
||||
obj.locale = validated_data['locale']
|
||||
obj.country_code = validated_data['country_code']
|
||||
obj.old_id = validated_data['old_id']
|
||||
obj.created = validated_data['created']
|
||||
obj.user_id = validated_data['user_id']
|
||||
obj.save()
|
||||
return obj
|
||||
|
||||
@staticmethod
|
||||
def get_user(data):
|
||||
|
|
@ -73,6 +84,6 @@ class NewsletterSubscriberSerializer(serializers.Serializer):
|
|||
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
|
||||
if user:
|
||||
return user.id
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -80,11 +80,11 @@ LOGGING = {
|
|||
'py.warnings': {
|
||||
'handlers': ['console'],
|
||||
},
|
||||
'django.db.backends': {
|
||||
'handlers': ['console', ],
|
||||
'level': 'DEBUG',
|
||||
'propagate': False,
|
||||
},
|
||||
# 'django.db.backends': {
|
||||
# 'handlers': ['console', ],
|
||||
# 'level': 'DEBUG',
|
||||
# 'propagate': False,
|
||||
# },
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user