Merge branch 'develop' into feature/guides
This commit is contained in:
commit
e2d71fca8f
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -28,3 +28,4 @@ celerybeat.pid
|
||||||
/gm_viktor.dump
|
/gm_viktor.dump
|
||||||
/docker-compose.dump.yml
|
/docker-compose.dump.yml
|
||||||
/gm_production_20191029.sql
|
/gm_production_20191029.sql
|
||||||
|
/apps/transfer/log
|
||||||
|
|
|
||||||
|
|
@ -65,7 +65,7 @@ class CollectionEstablishmentListView(CollectionListView):
|
||||||
# May raise a permission denied
|
# May raise a permission denied
|
||||||
self.check_object_permissions(self.request, collection)
|
self.check_object_permissions(self.request, collection)
|
||||||
|
|
||||||
return collection.establishments.all().annotate_in_favorites(self.request.user)
|
return collection.establishments.published().annotate_in_favorites(self.request.user)
|
||||||
|
|
||||||
|
|
||||||
# Guide
|
# Guide
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ class EstablishmentFilter(filters.FilterSet):
|
||||||
search = filters.CharFilter(method='search_text')
|
search = filters.CharFilter(method='search_text')
|
||||||
type = filters.CharFilter(method='by_type')
|
type = filters.CharFilter(method='by_type')
|
||||||
subtype = filters.CharFilter(method='by_subtype')
|
subtype = filters.CharFilter(method='by_subtype')
|
||||||
|
city_id = filters.CharFilter(field_name='address__city__id')
|
||||||
|
city_name = filters.CharFilter(field_name='address__city__name')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -24,6 +26,8 @@ class EstablishmentFilter(filters.FilterSet):
|
||||||
'search',
|
'search',
|
||||||
'type',
|
'type',
|
||||||
'subtype',
|
'subtype',
|
||||||
|
'city_id',
|
||||||
|
'city_name',
|
||||||
)
|
)
|
||||||
|
|
||||||
def search_text(self, queryset, name, value):
|
def search_text(self, queryset, name, value):
|
||||||
|
|
|
||||||
|
|
@ -132,7 +132,8 @@ class EstablishmentQuerySet(models.QuerySet):
|
||||||
|
|
||||||
def with_extended_address_related(self):
|
def with_extended_address_related(self):
|
||||||
"""Return qs with deeply related address models."""
|
"""Return qs with deeply related address models."""
|
||||||
return self.select_related('address__city', 'address__city__region', 'address__city__region__country',
|
return self.select_related('address__city', 'address__city__region',
|
||||||
|
'address__city__region__country',
|
||||||
'address__city__country')
|
'address__city__country')
|
||||||
|
|
||||||
def with_extended_related(self):
|
def with_extended_related(self):
|
||||||
|
|
@ -147,7 +148,8 @@ class EstablishmentQuerySet(models.QuerySet):
|
||||||
|
|
||||||
def with_es_related(self):
|
def with_es_related(self):
|
||||||
"""Return qs with related for ES indexing objects."""
|
"""Return qs with related for ES indexing objects."""
|
||||||
return self.select_related('address', 'establishment_type', 'address__city', 'address__city__country'). \
|
return self.select_related('address', 'establishment_type', 'address__city',
|
||||||
|
'address__city__country'). \
|
||||||
prefetch_related('tags', 'schedule')
|
prefetch_related('tags', 'schedule')
|
||||||
|
|
||||||
def search(self, value, locale=None):
|
def search(self, value, locale=None):
|
||||||
|
|
@ -246,7 +248,8 @@ class EstablishmentQuerySet(models.QuerySet):
|
||||||
'address__city__country': establishment.address.city.country
|
'address__city__country': establishment.address.city.country
|
||||||
}
|
}
|
||||||
if establishment.establishment_subtypes.exists():
|
if establishment.establishment_subtypes.exists():
|
||||||
filters.update({'establishment_subtypes__in': establishment.establishment_subtypes.all()})
|
filters.update(
|
||||||
|
{'establishment_subtypes__in': establishment.establishment_subtypes.all()})
|
||||||
|
|
||||||
return self.exclude(id=establishment.id) \
|
return self.exclude(id=establishment.id) \
|
||||||
.filter(**filters) \
|
.filter(**filters) \
|
||||||
|
|
@ -495,10 +498,6 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin,
|
||||||
schedule = models.ManyToManyField(to='timetable.Timetable', blank=True,
|
schedule = models.ManyToManyField(to='timetable.Timetable', blank=True,
|
||||||
verbose_name=_('Establishment schedule'),
|
verbose_name=_('Establishment schedule'),
|
||||||
related_name='schedule')
|
related_name='schedule')
|
||||||
# holidays_from = models.DateTimeField(verbose_name=_('Holidays from'),
|
|
||||||
# help_text=_('Holidays closing date from'))
|
|
||||||
# holidays_to = models.DateTimeField(verbose_name=_('Holidays to'),
|
|
||||||
# help_text=_('Holidays closing date to'))
|
|
||||||
transportation = models.TextField(blank=True, null=True, default=None,
|
transportation = models.TextField(blank=True, null=True, default=None,
|
||||||
verbose_name=_('Transportation'))
|
verbose_name=_('Transportation'))
|
||||||
collections = models.ManyToManyField(to='collection.Collection',
|
collections = models.ManyToManyField(to='collection.Collection',
|
||||||
|
|
@ -592,13 +591,6 @@ class Establishment(GalleryMixin, ProjectBaseMixin, URLImageMixin,
|
||||||
country = self.address.city.country
|
country = self.address.city.country
|
||||||
return country.low_price, country.high_price
|
return country.low_price, country.high_price
|
||||||
|
|
||||||
# todo: make via prefetch
|
|
||||||
# @property
|
|
||||||
# def subtypes(self):
|
|
||||||
# return EstablishmentSubType.objects.filter(
|
|
||||||
# subtype_establishment=self,
|
|
||||||
# establishment_type=self.establishment_type,
|
|
||||||
# establishment_type__use_subtypes=True)
|
|
||||||
|
|
||||||
def set_establishment_type(self, establishment_type):
|
def set_establishment_type(self, establishment_type):
|
||||||
self.establishment_type = establishment_type
|
self.establishment_type = establishment_type
|
||||||
|
|
@ -925,6 +917,12 @@ class EmployeeQuerySet(models.QuerySet):
|
||||||
"""Search by name or last_name."""
|
"""Search by name or last_name."""
|
||||||
return self._generic_search(value, ['name', 'last_name'])
|
return self._generic_search(value, ['name', 'last_name'])
|
||||||
|
|
||||||
|
def actual_establishment(self):
|
||||||
|
e = EstablishmentEmployee.objects.actual().filter(employee=self)
|
||||||
|
return self.prefetch_related(models.Prefetch('establishmentemployee_set',
|
||||||
|
queryset=EstablishmentEmployee.objects.actual()
|
||||||
|
)).all().distinct()
|
||||||
|
|
||||||
|
|
||||||
class Employee(BaseAttributes):
|
class Employee(BaseAttributes):
|
||||||
"""Employee model."""
|
"""Employee model."""
|
||||||
|
|
@ -933,7 +931,8 @@ class Employee(BaseAttributes):
|
||||||
null=True, blank=True, default=None,
|
null=True, blank=True, default=None,
|
||||||
verbose_name=_('User'))
|
verbose_name=_('User'))
|
||||||
name = models.CharField(max_length=255, verbose_name=_('Name'))
|
name = models.CharField(max_length=255, verbose_name=_('Name'))
|
||||||
last_name = models.CharField(max_length=255, verbose_name=_('Last Name'), null=True, default=None)
|
last_name = models.CharField(max_length=255, verbose_name=_('Last Name'), null=True,
|
||||||
|
default=None)
|
||||||
|
|
||||||
# SEX CHOICES
|
# SEX CHOICES
|
||||||
MALE = 0
|
MALE = 0
|
||||||
|
|
@ -943,11 +942,14 @@ class Employee(BaseAttributes):
|
||||||
(MALE, _('Male')),
|
(MALE, _('Male')),
|
||||||
(FEMALE, _('Female'))
|
(FEMALE, _('Female'))
|
||||||
)
|
)
|
||||||
sex = models.PositiveSmallIntegerField(choices=SEX_CHOICES, verbose_name=_('Sex'), null=True, default=None)
|
sex = models.PositiveSmallIntegerField(choices=SEX_CHOICES, verbose_name=_('Sex'), null=True,
|
||||||
birth_date = models.DateTimeField(editable=True, verbose_name=_('Birth date'), null=True, default=None)
|
default=None)
|
||||||
|
birth_date = models.DateTimeField(editable=True, verbose_name=_('Birth date'), null=True,
|
||||||
|
default=None)
|
||||||
email = models.EmailField(blank=True, null=True, default=None, verbose_name=_('Email'))
|
email = models.EmailField(blank=True, null=True, default=None, verbose_name=_('Email'))
|
||||||
phone = PhoneNumberField(null=True, default=None)
|
phone = PhoneNumberField(null=True, default=None)
|
||||||
toque_number = models.PositiveSmallIntegerField(verbose_name=_('Toque number'), null=True, default=None)
|
toque_number = models.PositiveSmallIntegerField(verbose_name=_('Toque number'), null=True,
|
||||||
|
default=None)
|
||||||
|
|
||||||
establishments = models.ManyToManyField(Establishment, related_name='employees',
|
establishments = models.ManyToManyField(Establishment, related_name='employees',
|
||||||
through=EstablishmentEmployee, )
|
through=EstablishmentEmployee, )
|
||||||
|
|
@ -998,25 +1000,6 @@ class ContactEmail(models.Model):
|
||||||
return f'{self.email}'
|
return f'{self.email}'
|
||||||
|
|
||||||
|
|
||||||
#
|
|
||||||
# class Wine(TranslatedFieldsMixin, models.Model):
|
|
||||||
# """Wine model."""
|
|
||||||
# establishment = models.ForeignKey(
|
|
||||||
# 'establishment.Establishment', verbose_name=_('establishment'),
|
|
||||||
# on_delete=models.CASCADE)
|
|
||||||
# bottles = models.IntegerField(_('bottles'))
|
|
||||||
# price_min = models.DecimalField(
|
|
||||||
# _('price min'), max_digits=14, decimal_places=2)
|
|
||||||
# price_max = models.DecimalField(
|
|
||||||
# _('price max'), max_digits=14, decimal_places=2)
|
|
||||||
# by_glass = models.BooleanField(_('by glass'))
|
|
||||||
# price_glass_min = models.DecimalField(
|
|
||||||
# _('price min'), max_digits=14, decimal_places=2)
|
|
||||||
# price_glass_max = models.DecimalField(
|
|
||||||
# _('price max'), max_digits=14, decimal_places=2)
|
|
||||||
#
|
|
||||||
|
|
||||||
|
|
||||||
class Plate(TranslatedFieldsMixin, models.Model):
|
class Plate(TranslatedFieldsMixin, models.Model):
|
||||||
"""Plate model."""
|
"""Plate model."""
|
||||||
STR_FIELD_NAME = 'name'
|
STR_FIELD_NAME = 'name'
|
||||||
|
|
|
||||||
|
|
@ -157,28 +157,6 @@ class ContactEmailBackSerializers(model_serializers.PlateSerializer):
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
# TODO: test decorator
|
|
||||||
@with_base_attributes
|
|
||||||
class EmployeeBackSerializers(serializers.ModelSerializer):
|
|
||||||
"""Employee serializers."""
|
|
||||||
|
|
||||||
awards = AwardSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = models.Employee
|
|
||||||
fields = [
|
|
||||||
'id',
|
|
||||||
'user',
|
|
||||||
'name',
|
|
||||||
'last_name',
|
|
||||||
'sex',
|
|
||||||
'birth_date',
|
|
||||||
'email',
|
|
||||||
'phone',
|
|
||||||
'toque_number',
|
|
||||||
'awards',
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class PositionBackSerializer(serializers.ModelSerializer):
|
class PositionBackSerializer(serializers.ModelSerializer):
|
||||||
"""Position Back serializer."""
|
"""Position Back serializer."""
|
||||||
|
|
@ -194,6 +172,64 @@ class PositionBackSerializer(serializers.ModelSerializer):
|
||||||
'index_name',
|
'index_name',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
# TODO: test decorator
|
||||||
|
@with_base_attributes
|
||||||
|
class EmployeeBackSerializers(serializers.ModelSerializer):
|
||||||
|
"""Employee serializers."""
|
||||||
|
public_mark = serializers.SerializerMethodField()
|
||||||
|
positions = serializers.SerializerMethodField()
|
||||||
|
establishment = serializers.SerializerMethodField()
|
||||||
|
awards = AwardSerializer(many=True, read_only=True)
|
||||||
|
|
||||||
|
|
||||||
|
def get_public_mark(self, obj):
|
||||||
|
"""Get last list actual public_mark"""
|
||||||
|
qs = obj.establishmentemployee_set.actual().order_by('-from_date')\
|
||||||
|
.values('establishment__public_mark').first()
|
||||||
|
return qs['establishment__public_mark']
|
||||||
|
|
||||||
|
|
||||||
|
def get_positions(self, obj):
|
||||||
|
"""Get last list actual positions"""
|
||||||
|
est_id = obj.establishmentemployee_set.actual().\
|
||||||
|
order_by('-from_date').first().establishment_id
|
||||||
|
|
||||||
|
qs = obj.establishmentemployee_set.actual()\
|
||||||
|
.filter(establishment_id=est_id)\
|
||||||
|
.prefetch_related('position').values('position')
|
||||||
|
|
||||||
|
positions = models.Position.objects.filter(id__in=[q['position'] for q in qs])
|
||||||
|
|
||||||
|
return [PositionBackSerializer(p).data for p in positions]
|
||||||
|
|
||||||
|
def get_establishment(self, obj):
|
||||||
|
"""Get last actual establishment"""
|
||||||
|
est = obj.establishmentemployee_set.actual().order_by('-from_date')\
|
||||||
|
.first().establishment
|
||||||
|
|
||||||
|
return {
|
||||||
|
"id": est.id,
|
||||||
|
"slug": est.slug
|
||||||
|
}
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.Employee
|
||||||
|
fields = [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'last_name',
|
||||||
|
'user',
|
||||||
|
'public_mark',
|
||||||
|
'positions',
|
||||||
|
'awards',
|
||||||
|
'establishment',
|
||||||
|
'sex',
|
||||||
|
'birth_date',
|
||||||
|
'email',
|
||||||
|
'phone',
|
||||||
|
'toque_number'
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
class EstablishmentEmployeeBackSerializer(serializers.ModelSerializer):
|
class EstablishmentEmployeeBackSerializer(serializers.ModelSerializer):
|
||||||
"""Establishment Employee serializer."""
|
"""Establishment Employee serializer."""
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,9 @@ class EstablishmentTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
name_translated = TranslatedField()
|
name_translated = TranslatedField()
|
||||||
default_image_url = serializers.ImageField(source='default_image.image',
|
default_image_url = serializers.ImageField(source='default_image.image',
|
||||||
allow_null=True)
|
allow_null=True)
|
||||||
|
preview_image = serializers.URLField(source='preview_image_url',
|
||||||
|
allow_null=True,
|
||||||
|
read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -110,6 +113,7 @@ class EstablishmentTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
'use_subtypes',
|
'use_subtypes',
|
||||||
'index_name',
|
'index_name',
|
||||||
'default_image_url',
|
'default_image_url',
|
||||||
|
'preview_image',
|
||||||
]
|
]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'name': {'write_only': True},
|
'name': {'write_only': True},
|
||||||
|
|
@ -135,6 +139,9 @@ class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
name_translated = TranslatedField()
|
name_translated = TranslatedField()
|
||||||
default_image_url = serializers.ImageField(source='default_image.image',
|
default_image_url = serializers.ImageField(source='default_image.image',
|
||||||
allow_null=True)
|
allow_null=True)
|
||||||
|
preview_image = serializers.URLField(source='preview_image_url',
|
||||||
|
allow_null=True,
|
||||||
|
read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -146,6 +153,7 @@ class EstablishmentSubTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
'establishment_type',
|
'establishment_type',
|
||||||
'index_name',
|
'index_name',
|
||||||
'default_image_url',
|
'default_image_url',
|
||||||
|
'preview_image',
|
||||||
]
|
]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
'name': {'write_only': True},
|
'name': {'write_only': True},
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ from utils.permissions import IsCountryAdmin
|
||||||
from utils.views import CreateDestroyGalleryViewMixin
|
from utils.views import CreateDestroyGalleryViewMixin
|
||||||
from rest_framework.permissions import IsAuthenticatedOrReadOnly
|
from rest_framework.permissions import IsAuthenticatedOrReadOnly
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.db import IntegrityError
|
||||||
from utils.serializers import ImageBaseSerializer
|
from utils.serializers import ImageBaseSerializer
|
||||||
from location.filters import RegionFilter
|
from location.filters import RegionFilter
|
||||||
|
|
||||||
|
|
@ -81,6 +82,15 @@ class CityGalleryCreateDestroyView(common.CityViewMixin,
|
||||||
|
|
||||||
return gallery
|
return gallery
|
||||||
|
|
||||||
|
def create(self, request, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
return super(CityGalleryCreateDestroyView, self).create(request, *args, **kwargs)
|
||||||
|
except IntegrityError as e:
|
||||||
|
if not 'unique constraint' in e.args[0]:
|
||||||
|
raise e
|
||||||
|
models.CityGallery.objects.filter(city=kwargs['pk'], is_main=request.data['is_main']).delete()
|
||||||
|
return super(CityGalleryCreateDestroyView, self).create(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
||||||
class CityGalleryListView(common.CityViewMixin,
|
class CityGalleryListView(common.CityViewMixin,
|
||||||
generics.ListAPIView):
|
generics.ListAPIView):
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,7 @@ class NewsListSerializer(NewsBaseSerializer):
|
||||||
|
|
||||||
fields = NewsBaseSerializer.Meta.fields + (
|
fields = NewsBaseSerializer.Meta.fields + (
|
||||||
'image',
|
'image',
|
||||||
|
'in_favorites',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -210,16 +211,23 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
|
||||||
"""Overridden validate method."""
|
"""Overridden validate method."""
|
||||||
if 'descriptions' in attrs:
|
if 'descriptions' in attrs:
|
||||||
descriptions = attrs.pop('descriptions')
|
descriptions = attrs.pop('descriptions')
|
||||||
|
locales = list(map(lambda x: x['locale'], descriptions))
|
||||||
status_to_bool = {
|
status_to_bool = {
|
||||||
'active': True,
|
'active': True,
|
||||||
'inactive': False,
|
'inactive': False,
|
||||||
}
|
}
|
||||||
attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions}
|
attrs['slugs'] = {obj['locale']: obj['slug'] for obj in descriptions if 'slug' in obj}
|
||||||
attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions}
|
attrs['title'] = {obj['locale']: obj['title'] for obj in descriptions if 'title' in obj}
|
||||||
attrs['locale_to_description_is_active'] = {
|
attrs['locale_to_description_is_active'] = {
|
||||||
obj['locale']: status_to_bool[obj['status']] for obj in descriptions
|
obj['locale']: status_to_bool[obj['status']] for obj in descriptions
|
||||||
}
|
}
|
||||||
attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions}
|
attrs['description'] = {obj['locale']: obj['text'] for obj in descriptions if 'text' in obj}
|
||||||
|
if self.context['request'].method == 'PATCH':
|
||||||
|
instance = models.News.objects.get(pk=self.context['request'].data['id'])
|
||||||
|
for key in ['slugs', 'title', 'locale_to_description_is_active', 'description']:
|
||||||
|
for locale in locales:
|
||||||
|
if not attrs[key].get(locale):
|
||||||
|
attrs[key][locale] = getattr(instance, key).get(locale)
|
||||||
return attrs
|
return attrs
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
|
|
|
||||||
|
|
@ -36,6 +36,9 @@ class ProductSubTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
read_only=True)
|
read_only=True)
|
||||||
default_image_url = serializers.ImageField(source='default_image.image',
|
default_image_url = serializers.ImageField(source='default_image.image',
|
||||||
allow_null=True)
|
allow_null=True)
|
||||||
|
preview_image = serializers.URLField(source='preview_image_url',
|
||||||
|
allow_null=True,
|
||||||
|
read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.ProductSubType
|
model = models.ProductSubType
|
||||||
|
|
@ -44,6 +47,7 @@ class ProductSubTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
'name_translated',
|
'name_translated',
|
||||||
'index_name_display',
|
'index_name_display',
|
||||||
'default_image_url',
|
'default_image_url',
|
||||||
|
'preview_image',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -52,6 +56,9 @@ class ProductTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
name_translated = TranslatedField()
|
name_translated = TranslatedField()
|
||||||
default_image_url = serializers.ImageField(source='default_image.image',
|
default_image_url = serializers.ImageField(source='default_image.image',
|
||||||
allow_null=True)
|
allow_null=True)
|
||||||
|
preview_image = serializers.URLField(source='preview_image_url',
|
||||||
|
allow_null=True,
|
||||||
|
read_only=True)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = models.ProductType
|
model = models.ProductType
|
||||||
|
|
@ -60,6 +67,7 @@ class ProductTypeBaseSerializer(serializers.ModelSerializer):
|
||||||
'name_translated',
|
'name_translated',
|
||||||
'index_name',
|
'index_name',
|
||||||
'default_image_url',
|
'default_image_url',
|
||||||
|
'preview_image',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ def transfer_text_review():
|
||||||
text__isnull=True
|
text__isnull=True
|
||||||
).exclude(
|
).exclude(
|
||||||
text__iexact=''
|
text__iexact=''
|
||||||
).values('review_id', 'locale', 'text')
|
).values('review_id', 'locale', 'text', 'updated_by', 'created_at', 'updated_at')
|
||||||
|
|
||||||
serialized_data = ReviewTextSerializer(data=list(queryset), many=True)
|
serialized_data = ReviewTextSerializer(data=list(queryset), many=True)
|
||||||
if serialized_data.is_valid():
|
if serialized_data.is_valid():
|
||||||
|
|
@ -142,5 +142,8 @@ data_types = {
|
||||||
],
|
],
|
||||||
"product_review": [
|
"product_review": [
|
||||||
transfer_product_reviews,
|
transfer_product_reviews,
|
||||||
|
],
|
||||||
|
"transfer_text_review": [
|
||||||
|
transfer_text_review,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,7 @@ class EstablishmentDocument(Document):
|
||||||
properties=OBJECT_FIELD_PROPERTIES),
|
properties=OBJECT_FIELD_PROPERTIES),
|
||||||
'index_name': fields.KeywordField(attr='index_name'),
|
'index_name': fields.KeywordField(attr='index_name'),
|
||||||
'default_image': fields.KeywordField(attr='default_image_url'),
|
'default_image': fields.KeywordField(attr='default_image_url'),
|
||||||
|
'preview_image_url': fields.KeywordField(),
|
||||||
})
|
})
|
||||||
establishment_subtypes = fields.ObjectField(
|
establishment_subtypes = fields.ObjectField(
|
||||||
properties={
|
properties={
|
||||||
|
|
@ -31,6 +32,7 @@ class EstablishmentDocument(Document):
|
||||||
'name': fields.ObjectField(attr='name_indexing'),
|
'name': fields.ObjectField(attr='name_indexing'),
|
||||||
'index_name': fields.KeywordField(attr='index_name'),
|
'index_name': fields.KeywordField(attr='index_name'),
|
||||||
'default_image': fields.KeywordField(attr='default_image_url'),
|
'default_image': fields.KeywordField(attr='default_image_url'),
|
||||||
|
'preview_image_url': fields.KeywordField(),
|
||||||
},
|
},
|
||||||
multi=True)
|
multi=True)
|
||||||
works_evening = fields.ListField(fields.IntegerField(
|
works_evening = fields.ListField(fields.IntegerField(
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ class ProductDocument(Document):
|
||||||
'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES),
|
'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES),
|
||||||
'index_name': fields.KeywordField(),
|
'index_name': fields.KeywordField(),
|
||||||
'default_image': fields.KeywordField(attr='default_image_url'),
|
'default_image': fields.KeywordField(attr='default_image_url'),
|
||||||
|
'preview_image_url': fields.KeywordField(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
subtypes = fields.ObjectField(
|
subtypes = fields.ObjectField(
|
||||||
|
|
@ -28,6 +29,7 @@ class ProductDocument(Document):
|
||||||
'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES),
|
'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES),
|
||||||
'index_name': fields.KeywordField(),
|
'index_name': fields.KeywordField(),
|
||||||
'default_image': fields.KeywordField(attr='default_image_url'),
|
'default_image': fields.KeywordField(attr='default_image_url'),
|
||||||
|
'preview_image_url': fields.KeywordField(),
|
||||||
},
|
},
|
||||||
multi=True
|
multi=True
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ class EstablishmentTypeSerializer(serializers.Serializer):
|
||||||
id = serializers.IntegerField()
|
id = serializers.IntegerField()
|
||||||
name_translated = serializers.SerializerMethodField()
|
name_translated = serializers.SerializerMethodField()
|
||||||
index_name = serializers.CharField()
|
index_name = serializers.CharField()
|
||||||
|
default_image = serializers.CharField()
|
||||||
|
preview_image_url = serializers.CharField()
|
||||||
|
|
||||||
def get_name_translated(self, obj):
|
def get_name_translated(self, obj):
|
||||||
if isinstance(obj, dict):
|
if isinstance(obj, dict):
|
||||||
|
|
@ -39,6 +41,8 @@ class ProductSubtypeDocumentSerializer(serializers.Serializer):
|
||||||
|
|
||||||
id = serializers.IntegerField()
|
id = serializers.IntegerField()
|
||||||
name_translated = serializers.SerializerMethodField()
|
name_translated = serializers.SerializerMethodField()
|
||||||
|
default_image = serializers.CharField()
|
||||||
|
preview_image_url = serializers.CharField()
|
||||||
|
|
||||||
def get_name_translated(self, obj):
|
def get_name_translated(self, obj):
|
||||||
if isinstance(obj, dict):
|
if isinstance(obj, dict):
|
||||||
|
|
@ -102,6 +106,8 @@ class ProductTypeSerializer(serializers.Serializer):
|
||||||
id = serializers.IntegerField()
|
id = serializers.IntegerField()
|
||||||
index_name = serializers.CharField()
|
index_name = serializers.CharField()
|
||||||
name_translated = serializers.SerializerMethodField()
|
name_translated = serializers.SerializerMethodField()
|
||||||
|
default_image = serializers.CharField()
|
||||||
|
preview_image_url = serializers.CharField()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_name_translated(obj):
|
def get_name_translated(obj):
|
||||||
|
|
|
||||||
|
|
@ -276,9 +276,6 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
|
||||||
},
|
},
|
||||||
'subtype': {
|
'subtype': {
|
||||||
'field': 'establishment_subtypes.index_name',
|
'field': 'establishment_subtypes.index_name',
|
||||||
'lookups': [
|
|
||||||
constants.LOOKUP_QUERY_IN,
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
'works_noon': {
|
'works_noon': {
|
||||||
'field': 'works_noon',
|
'field': 'works_noon',
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,8 @@ class Command(BaseCommand):
|
||||||
'setup_clean_db',
|
'setup_clean_db',
|
||||||
'languages', # №4 - перенос языков
|
'languages', # №4 - перенос языков
|
||||||
'set_unused_regions',
|
'set_unused_regions',
|
||||||
'update_fake_country_flag'
|
'update_fake_country_flag',
|
||||||
|
'transfer_text_review', # переводы для review с их авторами - запускать после overlook и product_review
|
||||||
]
|
]
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
|
@ -68,7 +69,8 @@ class Command(BaseCommand):
|
||||||
if len(data_type) != 1:
|
if len(data_type) != 1:
|
||||||
data_type = list(set(option for option in options.keys() if options[option]) & set(self.SHORT_DATA_TYPES))
|
data_type = list(set(option for option in options.keys() if options[option]) & set(self.SHORT_DATA_TYPES))
|
||||||
if len(data_type) != 1:
|
if len(data_type) != 1:
|
||||||
print("You must set correct option!\r\nYou can get options list with \r\n\r\n\tmanage.py help transfer\r\n")
|
print(
|
||||||
|
"You must set correct option!\r\nYou can get options list with \r\n\r\n\tmanage.py help transfer\r\n")
|
||||||
exit(1)
|
exit(1)
|
||||||
else:
|
else:
|
||||||
data_type = data_type[0]
|
data_type = data_type[0]
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
from review.models import Review
|
from review.models import Review, ReviewTextAuthor
|
||||||
from account.models import User
|
from account.models import User
|
||||||
from translation.models import Language
|
from translation.models import Language
|
||||||
from establishment.models import Establishment
|
from establishment.models import Establishment
|
||||||
|
|
@ -97,24 +97,41 @@ class ReviewTextSerializer(serializers.Serializer):
|
||||||
review_id = serializers.IntegerField()
|
review_id = serializers.IntegerField()
|
||||||
locale = serializers.CharField(allow_null=True)
|
locale = serializers.CharField(allow_null=True)
|
||||||
text = serializers.CharField()
|
text = serializers.CharField()
|
||||||
|
updated_by = serializers.IntegerField(allow_null=True)
|
||||||
|
created_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S')
|
||||||
|
updated_at = serializers.DateTimeField(format='%m-%d-%Y %H:%M:%S')
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
data.update({
|
data.update({
|
||||||
'new_text': self.get_text(data),
|
'new_text': self.get_text(data),
|
||||||
'review': self.get_review(data),
|
'review': self.get_review(data),
|
||||||
|
'author': self.get_author(data),
|
||||||
})
|
})
|
||||||
data.pop('review_id')
|
data.pop('review_id')
|
||||||
data.pop('locale')
|
|
||||||
data.pop('text')
|
data.pop('text')
|
||||||
return data
|
return data
|
||||||
|
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
review = validated_data['review']
|
review = validated_data['review']
|
||||||
|
author_payload = {
|
||||||
|
'review': review,
|
||||||
|
'author': validated_data['author'],
|
||||||
|
'locale': validated_data['locale'] or 'en-GB',
|
||||||
|
'created': validated_data['created_at'],
|
||||||
|
}
|
||||||
if review.text:
|
if review.text:
|
||||||
review.text.update(validated_data['new_text'])
|
review.text.update(validated_data['new_text'])
|
||||||
else:
|
else:
|
||||||
review.text = validated_data['new_text']
|
review.text = validated_data['new_text']
|
||||||
review.save()
|
review.save()
|
||||||
|
|
||||||
|
if validated_data['author'] and validated_data['locale']:
|
||||||
|
review_author, _ = ReviewTextAuthor.objects.update_or_create(
|
||||||
|
review=review,
|
||||||
|
locale=author_payload['locale'],
|
||||||
|
defaults=author_payload,
|
||||||
|
)
|
||||||
|
|
||||||
return review
|
return review
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -130,6 +147,12 @@ class ReviewTextSerializer(serializers.Serializer):
|
||||||
raise ValueError(f"Review not found with old_id {data['review_id']}: ")
|
raise ValueError(f"Review not found with old_id {data['review_id']}: ")
|
||||||
return review
|
return review
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def get_author(data):
|
||||||
|
user = User.objects.filter(old_id=data['updated_by']).first()
|
||||||
|
if user:
|
||||||
|
return user
|
||||||
|
|
||||||
|
|
||||||
class LanguageSerializer(serializers.ModelSerializer):
|
class LanguageSerializer(serializers.ModelSerializer):
|
||||||
LANGUAGES = {
|
LANGUAGES = {
|
||||||
|
|
|
||||||
|
|
@ -440,9 +440,11 @@ class HasTagsMixin(models.Model):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def visible_tags(self):
|
def visible_tags(self):
|
||||||
return self.tags.filter(category__public=True).prefetch_related('category',
|
return self.tags.filter(category__public=True).prefetch_related(
|
||||||
'translation', 'category__translation')\
|
'category',
|
||||||
.exclude(category__value_type='bool')
|
'translation',
|
||||||
|
'category__translation',
|
||||||
|
).exclude(category__value_type='bool')
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
"""Meta class."""
|
"""Meta class."""
|
||||||
|
|
@ -468,3 +470,8 @@ class TypeDefaultImageMixin:
|
||||||
"""Return image url."""
|
"""Return image url."""
|
||||||
if hasattr(self, 'default_image') and self.default_image:
|
if hasattr(self, 'default_image') and self.default_image:
|
||||||
return self.default_image.image.url
|
return self.default_image.image.url
|
||||||
|
|
||||||
|
@property
|
||||||
|
def preview_image_url(self):
|
||||||
|
if hasattr(self, 'default_image') and self.default_image:
|
||||||
|
return self.default_image.get_image_url(thumbnail_key='type_preview')
|
||||||
|
|
|
||||||
|
|
@ -409,6 +409,7 @@ SORL_THUMBNAIL_ALIASES = {
|
||||||
'city_xlarge': {'geometry_string': '560x560', 'crop': 'center'},
|
'city_xlarge': {'geometry_string': '560x560', 'crop': 'center'},
|
||||||
'city_detail': {'geometry_string': '1120x1120', 'crop': 'center'},
|
'city_detail': {'geometry_string': '1120x1120', 'crop': 'center'},
|
||||||
'city_original': {'geometry_string': '2048x1536', 'crop': 'center'},
|
'city_original': {'geometry_string': '2048x1536', 'crop': 'center'},
|
||||||
|
'type_preview': {'geometry_string': '300x260', 'crop': 'center'},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user