Merge branch 'develop' into feature/add_tag_product

This commit is contained in:
Виктор Гладких 2019-11-12 17:37:51 +03:00
commit 097bab4bb1
38 changed files with 672 additions and 90 deletions

View File

@ -6,4 +6,4 @@ from . import models
@admin.register(models.Comment)
class CommentModelAdmin(admin.ModelAdmin):
"""Model admin for model Comment"""
raw_id_fields = ('user', 'country')
raw_id_fields = ('user',)

View File

@ -0,0 +1,17 @@
# Generated by Django 2.2.7 on 2019-11-12 13:17
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('comment', '0004_comment_old_id'),
]
operations = [
migrations.RemoveField(
model_name='comment',
name='country',
),
]

View File

@ -4,10 +4,9 @@ from django.db import models
from django.utils.translation import gettext_lazy as _
from account.models import User
from translation.models import Language
from utils.models import ProjectBaseMixin
from utils.querysets import ContentTypeQuerySetMixin
from translation.models import Language
from location.models import Country
class CommentQuerySet(ContentTypeQuerySetMixin):
@ -34,7 +33,6 @@ class Comment(ProjectBaseMixin):
text = models.TextField(verbose_name=_('Comment text'))
mark = models.PositiveIntegerField(blank=True, null=True, default=None, verbose_name=_('Mark'))
user = models.ForeignKey('account.User', related_name='comments', on_delete=models.CASCADE, verbose_name=_('User'))
country = models.ForeignKey(Country, verbose_name=_('Country'), on_delete=models.SET_NULL, null=True)
old_id = models.IntegerField(null=True, blank=True, default=None)
content_type = models.ForeignKey(generic.ContentType, on_delete=models.CASCADE)

View File

@ -1,8 +1,7 @@
from pprint import pprint
from django.db.models import Q
from account.transfer_data import STOP_LIST
from account.models import User
from establishment.models import Establishment
from transfer.models import Comments
from transfer.serializers.comments import CommentSerializer
@ -10,19 +9,15 @@ from transfer.serializers.comments import CommentSerializer
def transfer_comments():
# В queryset исключены объекты по условию в связанные моделях
# см. transfer_establishment() и transfer_user()
queryset = Comments.objects.exclude(
Q(establishment__type='Wineyard') |
Q(establishment__location__timezone__isnull=True) |
Q(account__confirmed_at__isnull=True) |
Q(account__email__in=STOP_LIST)
).filter(
account__isnull=False,
mark__isnull=False
establishments = Establishment.objects.all().values_list('old_id', flat=True)
users = User.objects.all().values_list('old_id', flat=True)
queryset = Comments.objects.filter(
establishment_id__in=list(establishments),
account_id__in=list(users),
).only(
'id',
'comment',
'mark',
'locale',
'establishment_id',
'account_id',
)

View File

@ -0,0 +1,14 @@
from django.core.management.base import BaseCommand
from timetable.models import Timetable
class Command(BaseCommand):
help = '''Add closed_at, opening_at Timetable fields'''
def handle(self, *args, **options):
for tt in Timetable.objects.all():
end = tt.dinner_end or tt.lunch_end
start = tt.lunch_start or tt.dinner_start
if end or start:
tt.closed_at = end
tt.opening_at = start
tt.save()

View File

@ -0,0 +1,33 @@
# Generated by Django 2.2.7 on 2019-11-12 10:07
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('establishment', '0058_merge_20191106_0921'),
]
operations = [
migrations.CreateModel(
name='EstablishmentNote',
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')),
('old_id', models.PositiveIntegerField(blank=True, null=True)),
('text', models.TextField(verbose_name='text')),
('establishment', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='establishment_notes', to='establishment.Establishment', verbose_name='establishment')),
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='establishment_notes', to=settings.AUTH_USER_MODEL, verbose_name='author')),
],
options={
'verbose_name': 'product notes',
'verbose_name_plural': 'product note',
},
),
]

View File

@ -111,6 +111,19 @@ class EstablishmentQuerySet(models.QuerySet):
return self.select_related('address', 'establishment_type').\
prefetch_related('tags')
def with_schedule(self):
"""Return qs with related schedule."""
return self.prefetch_related('schedule')
def with_currency_related(self):
"""Return qs with related """
return self.prefetch_related('currency')
def with_extended_address_related(self):
"""Return qs with deeply related address models."""
return self.select_related('address__city', 'address__city__region', 'address__city__region__country',
'address__city__country')
def with_extended_related(self):
return self.select_related('establishment_type').\
prefetch_related('establishment_subtypes', 'awards', 'schedule',
@ -461,6 +474,11 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
""" Used for indexing working by day """
return [ret.weekday for ret in self.schedule.all() if ret.works_at_noon]
@property
def works_at_weekday(self):
""" Used for indexing by working whole day criteria """
return [ret.weekday for ret in self.schedule.all()]
@property
def works_evening(self):
""" Used for indexing working by day """
@ -520,6 +538,30 @@ class Establishment(ProjectBaseMixin, URLImageMixin, TranslatedFieldsMixin):
return self.products.wines()
class EstablishmentNoteQuerySet(models.QuerySet):
"""QuerySet for model EstablishmentNote."""
class EstablishmentNote(ProjectBaseMixin):
"""Note model for Establishment entity."""
old_id = models.PositiveIntegerField(null=True, blank=True)
text = models.TextField(verbose_name=_('text'))
establishment = models.ForeignKey(Establishment, on_delete=models.PROTECT,
related_name='establishment_notes',
verbose_name=_('establishment'))
user = models.ForeignKey('account.User', on_delete=models.PROTECT,
null=True,
related_name='establishment_notes',
verbose_name=_('author'))
objects = EstablishmentNoteQuerySet.as_manager()
class Meta:
"""Meta class."""
verbose_name_plural = _('product note')
verbose_name = _('product notes')
class Position(BaseAttributes, TranslatedFieldsMixin):
"""Position model."""

View File

@ -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
from location.serializers import AddressBaseSerializer, CitySerializer, AddressDetailSerializer
from main.serializers import AwardSerializer, CurrencySerializer
from tag.serializers import TagBaseSerializer
from timetable.serialziers import ScheduleRUDSerializer
@ -225,6 +225,19 @@ class EstablishmentBaseSerializer(ProjectModelSerializer):
'currency'
]
class EstablishmentListRetrieveSerializer(EstablishmentBaseSerializer):
"""Establishment with city serializer."""
address = AddressDetailSerializer()
schedule = ScheduleRUDSerializer(many=True, allow_null=True)
class Meta(EstablishmentBaseSerializer.Meta):
"""Meta class."""
fields = EstablishmentBaseSerializer.Meta.fields + [
'schedule',
]
class EstablishmentGeoSerializer(EstablishmentBaseSerializer):
"""Serializer for Geo view."""
@ -260,6 +273,8 @@ class EstablishmentDetailSerializer(EstablishmentBaseSerializer):
review = ReviewShortSerializer(source='last_published_review', allow_null=True)
employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees',
many=True)
address = AddressDetailSerializer(read_only=True)
menu = MenuSerializers(source='menu_set', many=True, read_only=True)
best_price_menu = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)
best_price_carte = serializers.DecimalField(max_digits=14, decimal_places=2, read_only=True)

View File

@ -4,8 +4,9 @@ from django.db.models import Q, F
from establishment.models import Establishment
from location.models import Address
from transfer.models import Establishments, Dishes
from transfer.serializers.establishment import EstablishmentSerializer
from transfer.models import Establishments, Dishes, EstablishmentNotes
from transfer.serializers.establishment import EstablishmentSerializer, \
EstablishmentNoteSerializer
from transfer.serializers.plate import PlateSerializer
@ -124,10 +125,26 @@ def transfer_establishment_addresses():
establishment.save()
def transfer_establishment_note():
errors = []
queryset = EstablishmentNotes.objects.exclude(text__exact='') \
.exclude(text__isnull=True) \
.exclude(establishment_id__isnull=True)
serialized_data = EstablishmentNoteSerializer(
data=list(queryset.values()),
many=True)
if serialized_data.is_valid():
serialized_data.save()
else:
for d in serialized_data.errors: errors.append(d) if d else None
pprint(f"transfer_establishment_note errors: {errors}")
data_types = {
"establishment": [
transfer_establishment,
],
"establishment_note": [transfer_establishment_note],
"location_establishment": [
transfer_establishment_addresses
],

View File

@ -32,7 +32,11 @@ class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView):
"""Resource for getting a list of establishments."""
filter_class = filters.EstablishmentFilter
serializer_class = serializers.EstablishmentBaseSerializer
serializer_class = serializers.EstablishmentListRetrieveSerializer
def get_queryset(self):
return super().get_queryset().with_schedule()\
.with_extended_address_related().with_currency_related()
class EstablishmentRetrieveView(EstablishmentMixinView, generics.RetrieveAPIView):

View File

@ -68,7 +68,7 @@ class CitySerializer(serializers.ModelSerializer):
queryset=models.Country.objects.all(),
write_only=True
)
country = CountrySerializer()
country = CountrySerializer(read_only=True)
class Meta:
model = models.City

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.4 on 2019-11-07 14:41
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('main', '0033_auto_20191106_0744'),
]
operations = [
migrations.AddField(
model_name='sitefeature',
name='nested',
field=models.ManyToManyField(to='main.SiteFeature'),
),
]

View File

@ -0,0 +1,14 @@
# Generated by Django 2.2.7 on 2019-11-12 12:18
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('main', '0034_sitefeature_nested'),
('main', '0034_auto_20191112_0104'),
]
operations = [
]

View File

@ -151,6 +151,7 @@ class SiteFeature(ProjectBaseMixin):
feature = models.ForeignKey(Feature, on_delete=models.PROTECT)
published = models.BooleanField(default=False, verbose_name=_('Published'))
main = models.BooleanField(default=False, verbose_name=_('Main'))
nested = models.ManyToManyField('self', symmetrical=False)
objects = SiteFeatureQuerySet.as_manager()

View File

@ -4,7 +4,7 @@ from rest_framework import serializers
from advertisement.serializers.web import AdvertisementSerializer
from location.serializers import CountrySerializer
from main import models
from utils.serializers import ProjectModelSerializer, TranslatedField
from utils.serializers import ProjectModelSerializer, TranslatedField, RecursiveFieldSerializer
class FeatureSerializer(serializers.ModelSerializer):
@ -27,6 +27,7 @@ class SiteFeatureSerializer(serializers.ModelSerializer):
priority = serializers.IntegerField(source='feature.priority')
route = serializers.CharField(source='feature.route.page_name')
source = serializers.IntegerField(source='feature.source')
nested = RecursiveFieldSerializer(many=True, allow_null=True)
class Meta:
"""Meta class."""
@ -36,8 +37,9 @@ class SiteFeatureSerializer(serializers.ModelSerializer):
'slug',
'priority',
'route',
'source'
)
'source',
'nested',
)
class CurrencySerializer(ProjectModelSerializer):

View File

@ -1,14 +1,21 @@
"""Filters from application News"""
import django_filters
from django_filters import rest_framework as filters
from django.utils.translation import gettext_lazy as _
from news import models
class NewsListFilterSet(django_filters.FilterSet):
class NewsListFilterSet(filters.FilterSet):
"""FilterSet for News list"""
is_highlighted = django_filters.BooleanFilter()
title = django_filters.CharFilter(method='by_title')
is_highlighted = filters.BooleanFilter()
title = filters.CharFilter(method='by_title')
tag_group = filters.ChoiceFilter(
choices=(
(models.News.RECIPES_TAG_VALUE, _('Recipes')),
),
method='by_tag_group'
)
class Meta:
"""Meta class"""
@ -16,8 +23,14 @@ class NewsListFilterSet(django_filters.FilterSet):
fields = (
'title',
'is_highlighted',
'tag_group',
)
def by_tag_group(self, queryset, name, value):
if value == models.News.RECIPES_TAG_VALUE:
queryset = queryset.recipe_news()
return queryset
def by_title(self, queryset, name, value):
"""Crappy search by title according to locale"""
if value:

View File

@ -53,6 +53,10 @@ class NewsQuerySet(TranslationQuerysetMixin):
"""Filter collection by country code."""
return self.filter(country__code=code)
def recipe_news(self):
"""Returns news with tag 'cook' qs."""
return self.filter(tags__value=News.RECIPES_TAG_VALUE)
def published(self):
"""Return only published news"""
now = timezone.now()
@ -127,6 +131,8 @@ class News(BaseAttributes, TranslatedFieldsMixin):
(PUBLISHED_EXCLUSIVE, _('Published exclusive')),
)
RECIPES_TAG_VALUE = 'cook'
old_id = models.PositiveIntegerField(_('old id'), blank=True, null=True, default=None)
news_type = models.ForeignKey(NewsType, on_delete=models.PROTECT,
verbose_name=_('news type'))

9
apps/news/urls/common.py Normal file
View File

@ -0,0 +1,9 @@
from django.urls import path
from news import views
common_urlpatterns = [
path('', views.NewsListView.as_view(), name='list'),
path('types/', views.NewsTypeListView.as_view(), name='type'),
path('slug/<slug:slug>/', views.NewsDetailView.as_view(), name='rud'),
path('slug/<slug:slug>/favorites/', views.NewsFavoritesCreateDestroyView.as_view(), name='create-destroy-favorites')
]

8
apps/news/urls/mobile.py Normal file
View File

@ -0,0 +1,8 @@
"""News app urlconf."""
from news.urls.common import common_urlpatterns
app_name = 'news'
urlpatterns = []
urlpatterns.extend(common_urlpatterns)

View File

@ -1,12 +1,8 @@
"""News app urlconf."""
from django.urls import path
from news import views
from news.urls.common import common_urlpatterns
app_name = 'news'
urlpatterns = [
path('', views.NewsListView.as_view(), name='list'),
path('types/', views.NewsTypeListView.as_view(), name='type'),
path('slug/<slug:slug>/', views.NewsDetailView.as_view(), name='rud'),
path('slug/<slug:slug>/favorites/', views.NewsFavoritesCreateDestroyView.as_view(), name='create-destroy-favorites')
]
urlpatterns = []
urlpatterns.extend(common_urlpatterns)

View File

@ -0,0 +1,37 @@
# Generated by Django 2.2.7 on 2019-11-12 10:07
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
('product', '0011_product_win_import_id'),
]
operations = [
migrations.RemoveField(
model_name='product',
name='win_import_id',
),
migrations.CreateModel(
name='ProductNote',
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')),
('old_id', models.PositiveIntegerField(blank=True, null=True)),
('text', models.TextField(verbose_name='text')),
('product', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='product_notes', to='product.Product', verbose_name='product')),
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='product_notes', to=settings.AUTH_USER_MODEL, verbose_name='author')),
],
options={
'verbose_name': 'product notes',
'verbose_name_plural': 'product note',
},
),
]

View File

@ -193,9 +193,6 @@ class Product(TranslatedFieldsMixin, BaseAttributes):
validators=[MinValueValidator(EARLIEST_VINTAGE_YEAR),
MaxValueValidator(LATEST_VINTAGE_YEAR)])
gallery = models.ManyToManyField('gallery.Image', through='ProductGallery')
win_import_id = models.CharField(max_length=255,
blank=True, null=True, default=None,
help_text=_('attribute from legacy db'))
reviews = generic.GenericRelation(to='review.Review')
comments = generic.GenericRelation(to='comment.Comment')
awards = generic.GenericRelation(to='main.Award', related_query_name='product')
@ -409,3 +406,27 @@ class ProductClassification(models.Model):
"""Meta class."""
verbose_name = _('product classification')
verbose_name_plural = _('product classifications')
class ProductNoteQuerySet(models.QuerySet):
"""QuerySet for model ProductNote."""
class ProductNote(ProjectBaseMixin):
"""Note model for Product entity."""
old_id = models.PositiveIntegerField(null=True, blank=True)
text = models.TextField(verbose_name=_('text'))
product = models.ForeignKey(Product, on_delete=models.PROTECT,
related_name='product_notes',
verbose_name=_('product'))
user = models.ForeignKey('account.User', on_delete=models.PROTECT,
null=True,
related_name='product_notes',
verbose_name=_('author'))
objects = ProductNoteQuerySet.as_manager()
class Meta:
"""Meta class."""
verbose_name_plural = _('product note')
verbose_name = _('product notes')

View File

@ -76,7 +76,7 @@ class ProductBaseSerializer(serializers.ModelSerializer):
subtypes = ProductSubTypeBaseSerializer(many=True)
establishment = EstablishmentShortSerializer()
tags = TagBaseSerializer(source='related_tags', many=True)
preview_image_url = serializers.ImageField(source='preview_main_image_url', allow_null=True)
preview_image_url = serializers.URLField(source='preview_main_image_url', allow_null=True)
class Meta:
"""Meta class."""

View File

@ -101,6 +101,7 @@ def transfer_wine_classifications():
def transfer_product():
errors = []
queryset = transfer_models.Products.objects.all()
serialized_data = product_serializers.ProductSerializer(
data=list(queryset.values()),
@ -108,26 +109,25 @@ def transfer_product():
if serialized_data.is_valid():
serialized_data.save()
else:
errors = []
for d in serialized_data.errors: errors.append(d) if d else None
pprint(f"transfer_product errors: {errors}")
def transfer_product_description():
pass
# queryset = transfer_models.Products.objects.all()
# serialized_data = product_serializers.ProductSerializer(
# data=list(queryset.values()),
# many=True)
# if serialized_data.is_valid():
# serialized_data.save()
# else:
# errors = []
# for d in serialized_data.errors: errors.append(d) if d else None
# pprint(f"transfer_product errors: {errors}")
def transfer_product_note():
errors = []
queryset = transfer_models.ProductNotes.objects.exclude(text='')
serialized_data = product_serializers.ProductNoteSerializer(
data=list(queryset.values()),
many=True)
if serialized_data.is_valid():
serialized_data.save()
else:
for d in serialized_data.errors: errors.append(d) if d else None
pprint(f"transfer_product_note errors: {errors}")
def transfer_plate():
errors = []
queryset = transfer_models.Merchandise.objects.all()
serialized_data = product_serializers.PlateSerializer(
data=list(queryset.values()),
@ -135,12 +135,12 @@ def transfer_plate():
if serialized_data.is_valid():
serialized_data.save()
else:
errors = []
for d in serialized_data.errors: errors.append(d) if d else None
pprint(f"transfer_plates errors: {errors}")
def transfer_plate_image():
errors = []
queryset = transfer_models.Merchandise.objects.all()
serialized_data = product_serializers.PlateImageSerializer(
data=list(queryset.values()),
@ -148,7 +148,6 @@ def transfer_plate_image():
if serialized_data.is_valid():
serialized_data.save()
else:
errors = []
for d in serialized_data.errors: errors.append(d) if d else None
pprint(f"transfer_plates_images errors: {errors}")
@ -166,9 +165,9 @@ data_types = {
"product": [
transfer_product,
],
# "product_description": [
# transfer_product_description,
# ],
"product_note": [
transfer_product_note,
],
"souvenir": [
transfer_plate,
transfer_plate_image,

View File

@ -37,6 +37,9 @@ class EstablishmentDocument(Document):
works_noon = fields.ListField(fields.IntegerField(
attr='works_noon'
))
works_at_weekday = fields.ListField(fields.IntegerField(
attr='works_at_weekday'
))
works_now = fields.BooleanField(attr='works_now')
tags = fields.ObjectField(
properties={
@ -65,7 +68,6 @@ class EstablishmentDocument(Document):
'number': fields.IntegerField(),
'postal_code': fields.KeywordField(),
'coordinates': fields.GeoPointField(attr='location_field_indexing'),
# todo: remove if not used
'city': fields.ObjectField(
properties={
'id': fields.IntegerField(),

View File

@ -19,10 +19,19 @@ class TagsDocumentSerializer(serializers.Serializer):
return get_translated_value(obj.label)
class CityDocumentShortSerializer(serializers.Serializer):
"""City serializer for ES Document,"""
id = serializers.IntegerField()
code = serializers.CharField(allow_null=True)
name = serializers.CharField()
class AddressDocumentSerializer(serializers.Serializer):
"""Address serializer for ES Document."""
id = serializers.IntegerField()
city = CityDocumentShortSerializer()
street_name_1 = serializers.CharField()
street_name_2 = serializers.CharField()
number = serializers.IntegerField()
@ -108,6 +117,7 @@ class EstablishmentDocumentSerializer(DocumentSerializer):
'schedule',
'works_noon',
'works_evening',
'works_at_weekday',
# 'works_now',
# 'collections',
# 'establishment_type',

View File

@ -2,13 +2,226 @@
from django_elasticsearch_dsl import fields
from utils.models import get_current_locale, get_default_locale
ALL_LOCALES_LIST = [
'af-ZA',
'am-ET',
'ar-AE',
'ar-BH',
'ar-DZ',
'ar-EG',
'ar-IQ',
'ar-JO',
'ar-KW',
'ar-LB',
'ar-LY',
'ar-MA',
'arn-CL',
'ar-OM',
'ar-QA',
'ar-SA',
'ar-SY',
'ar-TN',
'ar-YE',
'as-IN',
'az-Cyrl-AZ',
'az-Latn-AZ',
'ba-RU',
'be-BY',
'bg-BG',
'bn-BD',
'bn-IN',
'bo-CN',
'br-FR',
'bs-Cyrl-BA',
'bs-Latn-BA',
'ca-ES',
'co-FR',
'cs-CZ',
'cy-GB',
'da-DK',
'de-AT',
'de-CH',
'de-DE',
'de-LI',
'de-LU',
'dsb-DE',
'dv-MV',
'el-GR',
'en-029',
'en-AU',
'en-BZ',
'en-CA',
'en-GB',
'en-IE',
'en-IN',
'en-JM',
'en-MY',
'en-NZ',
'en-PH',
'en-SG',
'en-TT',
'en-US',
'en-ZA',
'en-ZW',
'es-AR',
'es-BO',
'es-CL',
'es-CO',
'es-CR',
'es-DO',
'es-EC',
'es-ES',
'es-GT',
'es-HN',
'es-MX',
'es-NI',
'es-PA',
'es-PE',
'es-PR',
'es-PY',
'es-SV',
'es-US',
'es-UY',
'es-VE',
'et-EE',
'eu-ES',
'fa-IR',
'fi-FI',
'fil-PH',
'fo-FO',
'fr-BE',
'fr-CA',
'fr-CH',
'fr-FR',
'fr-LU',
'fr-MC',
'fy-NL',
'ga-IE',
'gd-GB',
'gl-ES',
'gsw-FR',
'gu-IN',
'ha-Latn-NG',
'he-IL',
'hi-IN',
'hr-BA',
'hr-HR',
'hsb-DE',
'hu-HU',
'hy-AM',
'id-ID',
'ig-NG',
'ii-CN',
'is-IS',
'it-CH',
'it-IT',
'iu-Cans-CA',
'iu-Latn-CA',
'ja-JP',
'ka-GE',
'kk-KZ',
'kl-GL',
'km-KH',
'kn-IN',
'kok-IN',
'ko-KR',
'ky-KG',
'lb-LU',
'lo-LA',
'lt-LT',
'lv-LV',
'mi-NZ',
'mk-MK',
'ml-IN',
'mn-MN',
'mn-Mong-CN',
'moh-CA',
'mr-IN',
'ms-BN',
'ms-MY',
'mt-MT',
'nb-NO',
'ne-NP',
'nl-BE',
'nl-NL',
'nn-NO',
'nso-ZA',
'oc-FR',
'or-IN',
'pa-IN',
'pl-PL',
'prs-AF',
'ps-AF',
'pt-BR',
'pt-PT',
'qut-GT',
'quz-BO',
'quz-EC',
'quz-PE',
'rm-CH',
'ro-RO',
'ru-RU',
'rw-RW',
'sah-RU',
'sa-IN',
'se-FI',
'se-NO',
'se-SE',
'si-LK',
'sk-SK',
'sl-SI',
'sma-NO',
'sma-SE',
'smj-NO',
'smj-SE',
'smn-FI',
'sms-FI',
'sq-AL',
'sr-Cyrl-BA',
'sr-Cyrl-CS',
'sr-Cyrl-ME',
'sr-Cyrl-RS',
'sr-Latn-BA',
'sr-Latn-CS',
'sr-Latn-ME',
'sr-Latn-RS',
'sv-FI',
'sv-SE',
'sw-KE',
'syr-SY',
'ta-IN',
'te-IN',
'tg-Cyrl-TJ',
'th-TH',
'tk-TM',
'tn-ZA',
'tr-TR',
'tt-RU',
'tzm-Latn-DZ',
'ug-CN',
'uk-UA',
'ur-PK',
'uz-Cyrl-UZ',
'uz-Latn-UZ',
'vi-VN',
'wo-SN',
'xh-ZA',
'yo-NG',
'zh-CN',
'zh-HK',
'zh-MO',
'zh-SG',
'zh-TW',
'zu-ZA',
]
# object field properties
OBJECT_FIELD_PROPERTIES = {
OBJECT_FIELD_PROPERTIES = {locale: fields.TextField() for locale in ALL_LOCALES_LIST}
OBJECT_FIELD_PROPERTIES.update({
'en-GB': fields.TextField(analyzer='english'),
'ru-RU': fields.TextField(analyzer='russian'),
'fr-FR': fields.TextField(analyzer='french'),
}
'fr-FR': fields.TextField(analyzer='french')
})
# todo: refactor serializer
@ -17,10 +230,14 @@ def get_translated_value(value):
return None
elif not isinstance(value, dict):
field_dict = value.to_dict()
elif isinstance(value, dict):
else:
field_dict = value
value = field_dict.get(get_current_locale())
field_dict = {k: v for k, v in field_dict.items() if v is not None}
result = field_dict.get(get_current_locale(), None)
# fallback
if value is None:
value = field_dict.get(get_default_locale())
return value
if result is None:
result = field_dict.get(get_default_locale(), None)
if result is None:
values = list(field_dict.values())
result = values[0] if values else None
return result

View File

@ -156,6 +156,12 @@ class EstablishmentDocumentViewSet(BaseDocumentViewSet):
constants.LOOKUP_QUERY_IN,
],
},
'works_at_weekday': {
'field': 'works_at_weekday',
'lookups': [
constants.LOOKUP_QUERY_IN,
],
},
'works_evening': {
'field': 'works_evening',
'lookups': [

View File

@ -46,7 +46,7 @@ class Command(BaseCommand):
'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(

View File

@ -42,9 +42,7 @@ class TagBackOfficeSerializer(TagBaseSerializer):
class TagCategoryBaseSerializer(serializers.ModelSerializer):
"""Serializer for model TagCategory."""
# todo: refactor this
# label_translated = TranslatedField()
label_translated = serializers.CharField(source='index_name', read_only=True, allow_null=True)
label_translated = TranslatedField()
tags = TagBaseSerializer(many=True, read_only=True)
class Meta:

View File

@ -66,6 +66,7 @@ card = {
"fields": {
"Schedules": {
# нет аналогов для weekday, opening_at, closed_at
# upd: запустить команду add_closed_at_timetable. она заполнит opening_at, closed_at
"lunch_start": "lunch_start",
"lunch_end": "lunch_end",
"diner_start": "diner_start",

View File

@ -32,8 +32,9 @@ class Command(BaseCommand):
'inquiries', # №6 - перенос запросов оценок
'wine_characteristics',
'product',
'product_description',
'product_note',
'souvenir',
'establishment_note',
]
def handle(self, *args, **options):

View File

@ -447,6 +447,18 @@ class Establishments(MigrateMixin):
db_table = 'establishments'
class EstablishmentNotes(MigrateMixin):
using = 'legacy'
establishment_id = models.IntegerField(null=True, blank=True)
account_id = models.IntegerField(null=True, blank=True)
text = models.TextField(null=True)
class Meta:
managed = False
db_table = 'notes'
class Descriptions(MigrateMixin):
using = 'legacy'
@ -973,7 +985,7 @@ class Products(MigrateMixin):
class ProductNotes(MigrateMixin):
using = 'legacy'
product_id = models.ForeignKey(Products, on_delete=models.DO_NOTHING)
product_id = models.IntegerField(null=True, blank=True)
text = models.CharField(max_length=255)
win_import_id = models.CharField(max_length=255)

View File

@ -1,14 +1,13 @@
from rest_framework import serializers
from comment.models import Comment, User
from establishment.models import Establishment
from location.models import Country
class CommentSerializer(serializers.Serializer):
id = serializers.IntegerField()
comment = serializers.CharField()
mark = serializers.DecimalField(max_digits=4, decimal_places=2)
locale = serializers.CharField()
mark = serializers.DecimalField(max_digits=4, decimal_places=2, allow_null=True)
account_id = serializers.IntegerField()
establishment_id = serializers.CharField()
@ -16,14 +15,12 @@ class CommentSerializer(serializers.Serializer):
data.update({
'old_id': data.pop('id'),
'text': data.pop('comment'),
'mark': data['mark'] * -1 if data['mark'] < 0 else data['mark'],
'mark': self.get_mark(data),
'content_object': self.get_content_object(data),
'user': self.get_account(data),
'country': self.get_country(data),
})
data.pop('establishment_id')
data.pop('account_id')
data.pop('locale')
return data
def create(self, validated_data):
@ -47,10 +44,7 @@ class CommentSerializer(serializers.Serializer):
return user
@staticmethod
def get_country(data):
locale = data['locale']
country_code = locale[:locale.index("-")] if len(locale) > 2 else locale
country = Country.objects.filter(code=country_code).first()
if not country:
raise ValueError(f"Country not found with code {country_code}")
return country
def get_mark(data):
if not data['mark']:
return None
return data['mark'] * -1 if data['mark'] < 0 else data['mark']

View File

@ -1,16 +1,17 @@
from django.conf import settings
from django.core.exceptions import MultipleObjectsReturned, ValidationError
from django.db import transaction
from django.utils.text import slugify
from rest_framework import serializers
from establishment.models import Establishment, ContactEmail, ContactPhone, EstablishmentType, \
EstablishmentSubType
from account.models import User
from establishment.models import Establishment, ContactEmail, ContactPhone, \
EstablishmentType, EstablishmentSubType, EstablishmentNote
from location.models import Address
from timetable.models import Timetable
from utils.legacy_parser import parse_legacy_schedule_content
from utils.serializers import TimeZoneChoiceField
from utils.slug_generator import generate_unique_slug
from django.utils.text import slugify
class EstablishmentSerializer(serializers.ModelSerializer):
@ -173,3 +174,45 @@ class EstablishmentSerializer(serializers.ModelSerializer):
index_name=slugify(subtype_name),
establishment_type_id=establishment_type_id)
return subtype
class EstablishmentNoteSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
establishment_id = serializers.IntegerField()
account_id = serializers.IntegerField(allow_null=True)
text = serializers.CharField(allow_blank=True, allow_null=True)
class Meta:
model = EstablishmentNote
fields = (
'id',
'establishment_id',
'account_id',
'text',
)
def validate(self, attrs):
attrs['old_id'] = attrs['id']
attrs['establishment'] = self.get_establishment(attrs.pop('establishment_id'))
attrs['user'] = self.get_user(attrs.pop('account_id'))
return attrs
def create(self, validated_data):
qs = self.Meta.model.objects.filter(**validated_data)
establishment = validated_data.get('establishment')
if not qs.exists() and establishment:
obj = super().create(validated_data)
return obj
def get_establishment(self, old_id):
if old_id:
qs = Establishment.objects.filter(old_id=old_id)
if qs.exists():
return qs.first()
def get_user(self, old_id):
qs = User.objects.exclude(old_id__isnull=True).filter(old_id=old_id)
if qs.exists():
return qs.first()

View File

@ -541,3 +541,36 @@ class PlateImageSerializer(serializers.ModelSerializer):
product_qs = models.Product.objects.filter(old_id=product_id)
if product_qs.exists():
return product_qs.first()
class ProductNoteSerializer(serializers.ModelSerializer):
id = serializers.IntegerField()
product_id = serializers.IntegerField()
text = serializers.CharField(allow_blank=True)
class Meta:
model = models.ProductNote
fields = (
'id',
'product_id',
'text',
)
def validate(self, attrs):
attrs['old_id'] = attrs['id']
attrs['product'] = self.get_product(attrs.pop('product_id'))
return attrs
def create(self, validated_data):
qs = self.Meta.model.objects.filter(**validated_data)
product = validated_data.get('product')
if not qs.exists() and product:
return super().create(validated_data)
def get_product(self, old_id):
if old_id:
qs = models.Product.objects.filter(old_id=old_id)
if qs.exists():
return qs.first()

View File

@ -98,3 +98,9 @@ class FavoritesCreateSerializer(serializers.ModelSerializer):
@property
def slug(self):
return self.request.parser_context.get('kwargs').get('slug')
class RecursiveFieldSerializer(serializers.Serializer):
def to_representation(self, value):
serializer = self.parent.parent.__class__(value, context=self.context)
return serializer.data

View File

@ -12,6 +12,6 @@ urlpatterns = [
# path('advertisement/', include('advertisement.urls.web')),
# path('collection/', include('collection.urls.web')),
# path('establishments/', include('establishment.urls.web')),
# path('news/', include('news.urls.web')),
path('news/', include('news.urls.mobile')),
# path('partner/', include('partner.urls.web')),
]