Merge remote-tracking branch 'origin/develop' into owner_list
# Conflicts: # apps/transfer/models.py
This commit is contained in:
commit
f6427e732a
|
|
@ -10,4 +10,5 @@ urlpatterns = [
|
|||
path('user-role/', views.UserRoleLstView.as_view(), name='user-role-list-create'),
|
||||
path('user/', views.UserLstView.as_view(), name='user-create-list'),
|
||||
path('user/<int:id>/', views.UserRUDView.as_view(), name='user-rud'),
|
||||
path('user/<int:id>/csv', views.get_user_csv, name='user-csv'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
from django_filters.rest_framework import DjangoFilterBackend
|
||||
from rest_framework import generics, permissions
|
||||
from rest_framework.filters import OrderingFilter
|
||||
import csv
|
||||
from django.http import HttpResponse, HttpResponseNotFound
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
from account import models
|
||||
from account.models import User
|
||||
|
|
@ -46,3 +49,69 @@ class UserRUDView(generics.RetrieveUpdateDestroyAPIView):
|
|||
serializer_class = serializers.BackDetailUserSerializer
|
||||
permission_classes = (permissions.IsAdminUser,)
|
||||
lookup_field = 'id'
|
||||
|
||||
|
||||
def get_user_csv(request, id):
|
||||
# fields = ["id", "uuid", "nickname", "locale", "country_code", "city", "role", "consent_purpose", "consent_at",
|
||||
# "last_seen_at", "created_at", "updated_at", "email", "is_admin", "ezuser_id", "ez_user_id",
|
||||
# "encrypted_password", "reset_password_token", "reset_password_sent_at", "remember_created_at",
|
||||
# "sign_in_count", "current_sign_in_at", "last_sign_in_at", "current_sign_in_ip", "last_sign_in_ip",
|
||||
# "confirmation_token", "confirmed_at", "confirmation_sent_at", "unconfirmed_email", "webpush_subscription"]
|
||||
|
||||
# uuid == id
|
||||
#
|
||||
# Не найдены:
|
||||
# consent_purpose
|
||||
# consent_at
|
||||
# ezuser_id
|
||||
# ez_user_id
|
||||
# remember_created_at
|
||||
# sign_in_count
|
||||
# current_sign_in_at
|
||||
# current_sign_in_ip
|
||||
# last_sign_in_ip
|
||||
# confirmed_at
|
||||
# confirmation_sent_at
|
||||
# webpush_subscription
|
||||
#
|
||||
# country_code не получить - клиент не привязан к стране
|
||||
|
||||
try:
|
||||
user = User.objects.get(id=id)
|
||||
except User.DoesNotExist:
|
||||
return HttpResponseNotFound("User not found")
|
||||
|
||||
try:
|
||||
roles = " ".join([role for role in user.roles])
|
||||
except:
|
||||
roles = ""
|
||||
|
||||
token, _ = Token.objects.get_or_create(user=user)
|
||||
|
||||
fields = {
|
||||
"id": user.id,
|
||||
"uuid": user.id,
|
||||
"username": getattr(user, "username", ""),
|
||||
"locale": getattr(user, "locale", ""),
|
||||
"city": getattr(user, "city", ""),
|
||||
"role": roles,
|
||||
"created_at": getattr(user, "date_joined", ""),
|
||||
"updated_at": user.last_login,
|
||||
"email": user.email,
|
||||
"is_admin": user.is_superuser,
|
||||
"encrypted_password": user.password,
|
||||
"reset_password_token": token.key,
|
||||
"reset_password_sent_at": token.created, # TODO: не уверен в назначении поля, лучше проверить
|
||||
"last_sign_in_at": user.last_login, # Повтор?
|
||||
"confirmation_token": user.confirm_email_token,
|
||||
"unconfirmed_email": 1 if user.unconfirmed_email else 0
|
||||
}
|
||||
|
||||
response = HttpResponse(content_type='text/csv')
|
||||
response['Content-Disposition'] = f'attachment; filename="{user.email}.csv"'
|
||||
|
||||
writer = csv.writer(response)
|
||||
writer.writerow(fields.keys())
|
||||
writer.writerow(fields.values())
|
||||
|
||||
return response
|
||||
|
|
|
|||
|
|
@ -9,11 +9,17 @@ from utils.views import BindObjectMixin
|
|||
class CollectionViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
||||
"""ViewSet for Collection model."""
|
||||
|
||||
pagination_class = None
|
||||
# pagination_class = None
|
||||
permission_classes = (permissions.AllowAny,)
|
||||
queryset = models.Collection.objects.all()
|
||||
serializer_class = serializers.CollectionBackOfficeSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
"""Overridden method 'get_queryset'."""
|
||||
qs = models.Collection.objects.all().order_by('-created')
|
||||
if self.request.country_code:
|
||||
qs = qs.by_country_code(self.request.country_code)
|
||||
return qs
|
||||
|
||||
|
||||
class CollectionBackOfficeViewSet(mixins.CreateModelMixin,
|
||||
mixins.UpdateModelMixin,
|
||||
|
|
|
|||
17
apps/gallery/migrations/0007_auto_20191211_1528.py
Normal file
17
apps/gallery/migrations/0007_auto_20191211_1528.py
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-11 15:28
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gallery', '0006_merge_20191027_1758'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='image',
|
||||
options={'ordering': ['-modified'], 'verbose_name': 'Image', 'verbose_name_plural': 'Images'},
|
||||
),
|
||||
]
|
||||
|
|
@ -34,6 +34,7 @@ class Image(ProjectBaseMixin, SORLImageMixin, PlatformMixin):
|
|||
"""Meta class."""
|
||||
verbose_name = _('Image')
|
||||
verbose_name_plural = _('Images')
|
||||
ordering = ['-modified']
|
||||
|
||||
def __str__(self):
|
||||
"""String representation"""
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
from django.conf import settings
|
||||
from django.core.validators import MinValueValidator, MaxValueValidator
|
||||
from django.core.files.base import ContentFile
|
||||
from rest_framework import serializers
|
||||
from sorl.thumbnail.parsers import parse_crop
|
||||
from sorl.thumbnail.parsers import ThumbnailParseError
|
||||
from sorl.thumbnail import get_thumbnail
|
||||
from sorl.thumbnail.parsers import parse_crop, ThumbnailParseError
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from . import models
|
||||
|
|
@ -88,15 +89,23 @@ class CropImageSerializer(ImageSerializer):
|
|||
quality = validated_data.pop('quality')
|
||||
crop = validated_data.pop('crop')
|
||||
|
||||
crop_params = {
|
||||
'geometry': f'{width}x{height}',
|
||||
'quality': quality,
|
||||
'crop': crop,
|
||||
}
|
||||
cropped_image = self._image.get_cropped_image(**crop_params)
|
||||
image = self._image
|
||||
image.pk = None
|
||||
crop_params['geometry_string'] = crop_params.pop('geometry')
|
||||
resized = get_thumbnail(self._image.image, **crop_params)
|
||||
image.image.save(resized.name, ContentFile(resized.read()), True)
|
||||
image.save()
|
||||
|
||||
if image and width and height:
|
||||
setattr(image,
|
||||
'cropped_image',
|
||||
image.get_cropped_image(
|
||||
geometry=f'{width}x{height}',
|
||||
quality=quality,
|
||||
crop=crop))
|
||||
cropped_image)
|
||||
return image
|
||||
|
||||
@property
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ urlpatterns = [
|
|||
path('addresses/<int:pk>/', views.AddressRUDView.as_view(), name='address-RUD'),
|
||||
|
||||
path('cities/', views.CityListCreateView.as_view(), name='city-list-create'),
|
||||
path('cities/all/', views.CityListSearchView.as_view(), name='city-list-create'),
|
||||
path('cities/<int:pk>/', views.CityRUDView.as_view(), name='city-retrieve'),
|
||||
path('cities/<int:pk>/gallery/', views.CityGalleryListView.as_view(),
|
||||
name='gallery-list'),
|
||||
|
|
|
|||
|
|
@ -37,6 +37,15 @@ class CityListCreateView(common.CityViewMixin, generics.ListCreateAPIView):
|
|||
filter_class = filters.CityBackFilter
|
||||
|
||||
|
||||
class CityListSearchView(common.CityViewMixin, generics.ListCreateAPIView):
|
||||
"""Create view for model City."""
|
||||
serializer_class = serializers.CitySerializer
|
||||
permission_classes = [IsAuthenticatedOrReadOnly|IsCountryAdmin]
|
||||
queryset = models.City.objects.all()
|
||||
filter_class = filters.CityBackFilter
|
||||
pagination_class = None
|
||||
|
||||
|
||||
class CityRUDView(common.CityViewMixin, generics.RetrieveUpdateDestroyAPIView):
|
||||
"""RUD view for model City."""
|
||||
serializer_class = serializers.CitySerializer
|
||||
|
|
|
|||
38
apps/main/management/commands/add_panels.py
Normal file
38
apps/main/management/commands/add_panels.py
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
from django.core.management.base import BaseCommand
|
||||
from tqdm import tqdm
|
||||
|
||||
from account.models import User
|
||||
from main.models import Panel, SiteSettings
|
||||
from transfer.models import Panels
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = '''Add panels from legacy DB.'''
|
||||
|
||||
def handle(self, *args, **kwargs):
|
||||
objects = []
|
||||
deleted = 0
|
||||
panels_list = Panels.objects.filter(name__isnull=False)
|
||||
# remove existing panel
|
||||
exist_panel = Panel.objects.filter(old_id__isnull=False)
|
||||
if exist_panel.exists():
|
||||
deleted = exist_panel.count()
|
||||
exist_panel.delete()
|
||||
|
||||
for old_panel in tqdm(panels_list, desc='Add panels'):
|
||||
site = SiteSettings.objects.filter(old_id=old_panel.site_id).first()
|
||||
user = User.objects.filter(old_id=old_panel.site_id).first()
|
||||
if site:
|
||||
new_panel = Panel(
|
||||
old_id=old_panel.id,
|
||||
user=user,
|
||||
site=site,
|
||||
name=old_panel.name,
|
||||
display=old_panel.display,
|
||||
description=old_panel.description,
|
||||
query=old_panel.query,
|
||||
)
|
||||
objects.append(new_panel)
|
||||
Panel.objects.bulk_create(objects)
|
||||
self.stdout.write(
|
||||
self.style.WARNING(f'Created {len(objects)}/Deleted {deleted} footer objects.'))
|
||||
36
apps/main/migrations/0042_panel.py
Normal file
36
apps/main/migrations/0042_panel.py
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-12 12:00
|
||||
|
||||
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),
|
||||
('main', '0041_auto_20191211_0631'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Panel',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('created', models.DateTimeField(default=django.utils.timezone.now, editable=False, verbose_name='Date created')),
|
||||
('modified', models.DateTimeField(auto_now=True, verbose_name='Date updated')),
|
||||
('name', models.CharField(max_length=255, verbose_name='name')),
|
||||
('display', models.CharField(blank=True, choices=[('table', 'table'), ('table', 'mailing')], default=None, max_length=255, null=True, verbose_name='display')),
|
||||
('description', models.CharField(blank=True, default=None, max_length=255, null=True, verbose_name='description')),
|
||||
('query', models.TextField(blank=True, default=None, null=True, verbose_name='query')),
|
||||
('old_id', models.IntegerField(blank=True, default=None, null=True, verbose_name='old id')),
|
||||
('site', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='main.SiteSettings', verbose_name='site')),
|
||||
('user', models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL, verbose_name='user')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'panel',
|
||||
'verbose_name_plural': 'panels',
|
||||
},
|
||||
),
|
||||
]
|
||||
|
|
@ -361,3 +361,46 @@ class Footer(ProjectBaseMixin):
|
|||
)
|
||||
about_us = models.TextField(_('about_us'))
|
||||
copyright = models.TextField(_('copyright'))
|
||||
|
||||
|
||||
class PanelQuerySet(models.QuerySet):
|
||||
"""Panels QuerySet."""
|
||||
|
||||
|
||||
class Panel(ProjectBaseMixin):
|
||||
"""Custom panel model with stored SQL query."""
|
||||
TABLE = 'table'
|
||||
MAILING = 'table'
|
||||
|
||||
DISPLAY_CHOICES = (
|
||||
(TABLE, _('table')),
|
||||
(MAILING, _('mailing'))
|
||||
)
|
||||
name = models.CharField(_('name'), max_length=255)
|
||||
display = models.CharField(
|
||||
_('display'), max_length=255, choices=DISPLAY_CHOICES,
|
||||
blank=True, null=True, default=None
|
||||
)
|
||||
description = models.CharField(
|
||||
_('description'), max_length=255, blank=True, null=True, default=None)
|
||||
query = models.TextField(_('query'), blank=True, null=True, default=None)
|
||||
user = models.ForeignKey(
|
||||
'account.User', verbose_name=_('user'), null=True,
|
||||
on_delete=models.SET_NULL)
|
||||
site = models.ForeignKey(
|
||||
'main.SiteSettings', verbose_name=_('site'), null=True,
|
||||
on_delete=models.SET_NULL)
|
||||
old_id = models.IntegerField(
|
||||
_('old id'), null=True, blank=True, default=None)
|
||||
|
||||
objects = PanelQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('panel')
|
||||
verbose_name_plural = _('panels')
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def execute_query(self):
|
||||
pass
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ from rest_framework import serializers
|
|||
from location.serializers import CountrySerializer
|
||||
from main import models
|
||||
from utils.serializers import ProjectModelSerializer, TranslatedField, RecursiveFieldSerializer
|
||||
from account.serializers.back import BackUserSerializer
|
||||
from account.models import User
|
||||
|
||||
|
||||
class FeatureSerializer(serializers.ModelSerializer):
|
||||
|
|
@ -265,8 +267,32 @@ class PageTypeBaseSerializer(serializers.ModelSerializer):
|
|||
|
||||
|
||||
class ContentTypeBackSerializer(serializers.ModelSerializer):
|
||||
"""Serializer fro model ContentType."""
|
||||
"""Serializer for model ContentType."""
|
||||
|
||||
class Meta:
|
||||
model = ContentType
|
||||
fields = '__all__'
|
||||
|
||||
|
||||
class PanelSerializer(serializers.ModelSerializer):
|
||||
"""Serializer for Custom panel."""
|
||||
user_id = serializers.PrimaryKeyRelatedField(
|
||||
queryset=User.objects.all(),
|
||||
source='user',
|
||||
write_only=True
|
||||
)
|
||||
user = BackUserSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = models.Panel
|
||||
fields = [
|
||||
'id',
|
||||
'name',
|
||||
'display',
|
||||
'description',
|
||||
'query',
|
||||
'created',
|
||||
'modified',
|
||||
'user',
|
||||
'user_id'
|
||||
]
|
||||
|
|
|
|||
|
|
@ -21,7 +21,11 @@ urlpatterns = [
|
|||
path('footer/', views.FooterBackView.as_view(), name='footer-list-create'),
|
||||
path('footer/<int:pk>/', views.FooterRUDBackView.as_view(), name='footer-rud'),
|
||||
path('page-types/', views.PageTypeListCreateView.as_view(),
|
||||
name='page-types-list-create')
|
||||
name='page-types-list-create'),
|
||||
path('panels/', views.PanelsListCreateView.as_view(), name='panels'),
|
||||
path('panels/<int:pk>/', views.PanelsListCreateView.as_view(), name='panels-rud'),
|
||||
# path('panels/<int:pk>/execute/', views.PanelsView.as_view(), name='panels-execute')
|
||||
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ from rest_framework import generics, permissions
|
|||
|
||||
from main import serializers
|
||||
from main.filters import AwardFilter
|
||||
from main.models import Award, Footer, PageType
|
||||
from main.models import Award, Footer, PageType, Panel
|
||||
from main.views import SiteSettingsView, SiteListView
|
||||
|
||||
|
||||
|
|
@ -89,3 +89,21 @@ class PageTypeListCreateView(generics.ListCreateAPIView):
|
|||
pagination_class = None
|
||||
serializer_class = serializers.PageTypeBaseSerializer
|
||||
queryset = PageType.objects.all()
|
||||
|
||||
|
||||
class PanelsListCreateView(generics.ListCreateAPIView):
|
||||
"""Custom panels view."""
|
||||
permission_classes = (
|
||||
permissions.IsAdminUser,
|
||||
)
|
||||
serializer_class = serializers.PanelSerializer
|
||||
queryset = Panel.objects.all()
|
||||
|
||||
|
||||
class PanelsRUDView(generics.RetrieveUpdateDestroyAPIView):
|
||||
"""Custom panels view."""
|
||||
permission_classes = (
|
||||
permissions.IsAdminUser,
|
||||
)
|
||||
serializer_class = serializers.PanelSerializer
|
||||
queryset = Panel.objects.all()
|
||||
|
|
@ -70,9 +70,6 @@ class CarouselListView(generics.ListAPIView):
|
|||
|
||||
def get_queryset(self):
|
||||
country_code = self.request.country_code
|
||||
if hasattr(settings, 'CAROUSEL_ITEMS') and country_code in settings.INTERNATIONAL_COUNTRY_CODES:
|
||||
qs = models.Carousel.objects.filter(id__in=settings.CAROUSEL_ITEMS)
|
||||
return qs
|
||||
qs = models.Carousel.objects.is_parsed().active()
|
||||
if country_code:
|
||||
qs = qs.by_country_code(country_code)
|
||||
|
|
|
|||
18
apps/news/migrations/0041_auto_20191211_1528.py
Normal file
18
apps/news/migrations/0041_auto_20191211_1528.py
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-11 15:28
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('gallery', '0007_auto_20191211_1528'),
|
||||
('news', '0040_remove_news_slug'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='newsgallery',
|
||||
unique_together={('news', 'image')},
|
||||
),
|
||||
]
|
||||
|
|
@ -320,4 +320,4 @@ class NewsGallery(IntermediateGalleryModelMixin):
|
|||
"""NewsGallery meta class."""
|
||||
verbose_name = _('news gallery')
|
||||
verbose_name_plural = _('news galleries')
|
||||
unique_together = (('news', 'is_main'), ('news', 'image'))
|
||||
unique_together = [['news', 'image'],]
|
||||
|
|
|
|||
|
|
@ -243,6 +243,16 @@ class NewsBackOfficeGallerySerializer(serializers.ModelSerializer):
|
|||
"""Get url kwargs from request."""
|
||||
return self.context.get('request').parser_context.get('kwargs')
|
||||
|
||||
def create(self, validated_data):
|
||||
news_pk = self.get_request_kwargs().get('pk')
|
||||
image_id = self.get_request_kwargs().get('image_id')
|
||||
qs = models.NewsGallery.objects.filter(image_id=image_id, news_id=news_pk)
|
||||
instance = qs.first()
|
||||
if instance:
|
||||
qs.update(**validated_data)
|
||||
return instance
|
||||
return super().create(validated_data)
|
||||
|
||||
def validate(self, attrs):
|
||||
"""Override validate method."""
|
||||
news_pk = self.get_request_kwargs().get('pk')
|
||||
|
|
@ -259,8 +269,8 @@ class NewsBackOfficeGallerySerializer(serializers.ModelSerializer):
|
|||
news = news_qs.first()
|
||||
image = image_qs.first()
|
||||
|
||||
if image in news.gallery.all():
|
||||
raise serializers.ValidationError({'detail': _('Image is already added.')})
|
||||
# if image in news.gallery.all():
|
||||
# raise serializers.ValidationError({'detail': _('Image is already added.')})
|
||||
|
||||
attrs['news'] = news
|
||||
attrs['image'] = image
|
||||
|
|
|
|||
19
apps/product/migrations/0021_auto_20191212_0926.py
Normal file
19
apps/product/migrations/0021_auto_20191212_0926.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
# Generated by Django 2.2.7 on 2019-12-12 09:26
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('product', '0020_merge_20191209_0911'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='product',
|
||||
name='product_type',
|
||||
field=models.ForeignKey(blank=True, default=None, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='products', to='product.ProductType', verbose_name='Type'),
|
||||
),
|
||||
]
|
||||
|
|
@ -171,7 +171,7 @@ class Product(GalleryModelMixin, TranslatedFieldsMixin, BaseAttributes,
|
|||
default=None, help_text='{"en-GB":"some text"}')
|
||||
available = models.BooleanField(_('available'), default=True)
|
||||
product_type = models.ForeignKey(ProductType, on_delete=models.PROTECT,
|
||||
null=True,
|
||||
null=True, blank=True, default=None,
|
||||
related_name='products', verbose_name=_('Type'))
|
||||
subtypes = models.ManyToManyField(ProductSubType, blank=True,
|
||||
related_name='products',
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ from search_indexes.utils import OBJECT_FIELD_PROPERTIES
|
|||
from product import models
|
||||
|
||||
ProductIndex = Index(settings.ELASTICSEARCH_INDEX_NAMES.get(__name__, 'product'))
|
||||
ProductIndex.settings(number_of_shards=5, number_of_replicas=2, mapping={'total_fields':{'limit': 3000}})
|
||||
ProductIndex.settings(number_of_shards=5, number_of_replicas=2, mapping={'total_fields': {'limit': 3000}})
|
||||
|
||||
|
||||
@ProductIndex.doc_type
|
||||
|
|
@ -14,12 +14,13 @@ class ProductDocument(Document):
|
|||
|
||||
description = fields.ObjectField(attr='description_indexing',
|
||||
properties=OBJECT_FIELD_PROPERTIES)
|
||||
product_type = fields.ObjectField(properties={
|
||||
'id': fields.IntegerField(),
|
||||
'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES),
|
||||
'index_name': fields.KeywordField(),
|
||||
'use_subtypes': fields.BooleanField(),
|
||||
})
|
||||
product_type = fields.ObjectField(
|
||||
properties={
|
||||
'id': fields.IntegerField(),
|
||||
'name': fields.ObjectField(attr='name_indexing', properties=OBJECT_FIELD_PROPERTIES),
|
||||
'index_name': fields.KeywordField(),
|
||||
},
|
||||
)
|
||||
subtypes = fields.ObjectField(
|
||||
properties={
|
||||
'id': fields.IntegerField(),
|
||||
|
|
@ -54,15 +55,12 @@ class ProductDocument(Document):
|
|||
),
|
||||
'address': fields.ObjectField(
|
||||
properties={
|
||||
'city': fields.ObjectField(
|
||||
properties={
|
||||
'country': fields.ObjectField(
|
||||
properties={
|
||||
'code': fields.KeywordField()
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
'id': fields.IntegerField(),
|
||||
'street_name_1': fields.TextField(
|
||||
fields={'raw': fields.KeywordField()}
|
||||
),
|
||||
'postal_code': fields.KeywordField(),
|
||||
'coordinates': fields.GeoPointField(attr='location_field_indexing'),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
|
@ -155,7 +153,7 @@ class ProductDocument(Document):
|
|||
name_ru = fields.TextField(attr='display_name', analyzer='russian')
|
||||
name_fr = fields.TextField(attr='display_name', analyzer='french')
|
||||
favorites_for_users = fields.ListField(field=fields.IntegerField())
|
||||
created = fields.DateField(attr='created') # publishing date (?)
|
||||
created = fields.DateField(attr='created') # publishing date (?)
|
||||
|
||||
class Django:
|
||||
model = models.Product
|
||||
|
|
|
|||
|
|
@ -40,6 +40,8 @@ class ProductSubtypeDocumentSerializer(serializers.Serializer):
|
|||
name_translated = serializers.SerializerMethodField()
|
||||
|
||||
def get_name_translated(self, obj):
|
||||
if isinstance(obj, dict):
|
||||
return get_translated_value(obj.get('name'))
|
||||
return get_translated_value(obj.name)
|
||||
|
||||
|
||||
|
|
@ -93,7 +95,7 @@ class TagDocumentSerializer(serializers.Serializer):
|
|||
return get_translated_value(obj.label)
|
||||
|
||||
|
||||
class ProductTypeDocumentSerializer(serializers.Serializer):
|
||||
class ProductTypeSerializer(serializers.Serializer):
|
||||
"""Product type ES document serializer."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
|
|
@ -102,8 +104,13 @@ class ProductTypeDocumentSerializer(serializers.Serializer):
|
|||
|
||||
@staticmethod
|
||||
def get_name_translated(obj):
|
||||
if isinstance(obj, dict):
|
||||
return get_translated_value(obj.get('name'))
|
||||
return get_translated_value(obj.name)
|
||||
|
||||
def get_attribute(self, instance):
|
||||
return instance.product_type if instance and instance.product_type else None
|
||||
|
||||
|
||||
class CityDocumentShortSerializer(serializers.Serializer):
|
||||
"""City serializer for ES Document,"""
|
||||
|
|
@ -114,7 +121,6 @@ class CityDocumentShortSerializer(serializers.Serializer):
|
|||
|
||||
|
||||
class CountryDocumentSerializer(serializers.Serializer):
|
||||
|
||||
id = serializers.IntegerField()
|
||||
code = serializers.CharField(allow_null=True)
|
||||
svg_image = serializers.CharField()
|
||||
|
|
@ -122,11 +128,12 @@ class CountryDocumentSerializer(serializers.Serializer):
|
|||
|
||||
@staticmethod
|
||||
def get_name_translated(obj):
|
||||
if isinstance(obj, dict):
|
||||
return get_translated_value(obj.get('name'))
|
||||
return get_translated_value(obj.name)
|
||||
|
||||
|
||||
class AnotherCityDocumentShortSerializer(CityDocumentShortSerializer):
|
||||
|
||||
country = CountryDocumentSerializer()
|
||||
|
||||
def to_representation(self, instance):
|
||||
|
|
@ -136,19 +143,6 @@ class AnotherCityDocumentShortSerializer(CityDocumentShortSerializer):
|
|||
return None
|
||||
|
||||
|
||||
class ProductEstablishmentDocumentSerializer(serializers.Serializer):
|
||||
"""Related to Product Establishment ES document serializer."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
index_name = serializers.CharField()
|
||||
city = AnotherCityDocumentShortSerializer()
|
||||
|
||||
def get_attribute(self, instance):
|
||||
return instance.establishment if instance and instance.establishment else None
|
||||
|
||||
|
||||
class AddressDocumentSerializer(serializers.Serializer):
|
||||
"""Address serializer for ES Document."""
|
||||
|
||||
|
|
@ -171,6 +165,28 @@ class AddressDocumentSerializer(serializers.Serializer):
|
|||
return None
|
||||
|
||||
|
||||
class PSAddressDocumentSerializer(serializers.Serializer):
|
||||
"""Address serializer for ES Document."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
street_name_1 = serializers.CharField()
|
||||
postal_code = serializers.CharField()
|
||||
|
||||
|
||||
class ProductEstablishmentSerializer(serializers.Serializer):
|
||||
"""Related to Product Establishment ES document serializer."""
|
||||
|
||||
id = serializers.IntegerField()
|
||||
name = serializers.CharField()
|
||||
slug = serializers.CharField()
|
||||
index_name = serializers.CharField()
|
||||
city = AnotherCityDocumentShortSerializer()
|
||||
address = PSAddressDocumentSerializer(allow_null=True)
|
||||
|
||||
def get_attribute(self, instance):
|
||||
return instance.establishment if instance and instance.establishment else None
|
||||
|
||||
|
||||
class ScheduleDocumentSerializer(serializers.Serializer):
|
||||
"""Schedule serializer for ES Document"""
|
||||
|
||||
|
|
@ -285,15 +301,15 @@ class EstablishmentDocumentSerializer(InFavoritesMixin, DocumentSerializer):
|
|||
)
|
||||
|
||||
|
||||
class ProductDocumentSerializer(InFavoritesMixin, DocumentSerializer):
|
||||
class ProductDocumentSerializer(InFavoritesMixin):
|
||||
"""Product document serializer"""
|
||||
|
||||
tags = TagsDocumentSerializer(many=True, source='related_tags')
|
||||
subtypes = ProductSubtypeDocumentSerializer(many=True, allow_null=True)
|
||||
wine_colors = TagDocumentSerializer(many=True)
|
||||
grape_variety = TagDocumentSerializer(many=True)
|
||||
product_type = ProductTypeDocumentSerializer(allow_null=True)
|
||||
establishment_detail = ProductEstablishmentDocumentSerializer(source='establishment', allow_null=True)
|
||||
product_type = ProductTypeSerializer(allow_null=True)
|
||||
establishment_detail = ProductEstablishmentSerializer(source='establishment', allow_null=True)
|
||||
wine_origins = WineOriginSerializer(many=True)
|
||||
|
||||
class Meta:
|
||||
|
|
@ -317,7 +333,6 @@ class ProductDocumentSerializer(InFavoritesMixin, DocumentSerializer):
|
|||
'subtypes',
|
||||
'wine_colors',
|
||||
'grape_variety',
|
||||
'establishment_detail',
|
||||
'average_price',
|
||||
'created',
|
||||
'wine_origins',
|
||||
|
|
|
|||
|
|
@ -12,8 +12,8 @@ def update_document(sender, **kwargs):
|
|||
instance = kwargs['instance']
|
||||
|
||||
app_label_model_name_to_filter = {
|
||||
('location','country'): 'address__city__country',
|
||||
('location','city'): 'address__city',
|
||||
('location', 'country'): 'address__city__country',
|
||||
('location', 'city'): 'address__city',
|
||||
('location', 'address'): 'address',
|
||||
# todo: remove after migration
|
||||
('establishment', 'establishmenttype'): 'establishment_type',
|
||||
|
|
@ -34,8 +34,8 @@ def update_news(sender, **kwargs):
|
|||
model_name = sender._meta.model_name
|
||||
instance = kwargs['instance']
|
||||
app_label_model_name_to_filter = {
|
||||
('location','country'): 'country',
|
||||
('news','newstype'): 'news_type',
|
||||
('location', 'country'): 'country',
|
||||
('news', 'newstype'): 'news_type',
|
||||
('tag', 'tag'): 'tags',
|
||||
}
|
||||
filter_name = app_label_model_name_to_filter.get((app_label, model_name))
|
||||
|
|
@ -52,9 +52,9 @@ def update_product(sender, **kwargs):
|
|||
model_name = sender._meta.model_name
|
||||
instance = kwargs['instance']
|
||||
app_label_model_name_to_filter = {
|
||||
('product','productstandard'): 'standards',
|
||||
('product', 'productstandard'): 'standards',
|
||||
('product', 'producttype'): 'product_type',
|
||||
('tag','tag'): 'tags',
|
||||
('tag', 'tag'): 'tags',
|
||||
('location', 'wineregion'): 'wine_region',
|
||||
('location', 'winesubregion'): 'wine_sub_region',
|
||||
('location', 'winevillage'): 'wine_village',
|
||||
|
|
|
|||
|
|
@ -78,9 +78,30 @@ class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
|||
result_list = serializer.data
|
||||
query_params = request.query_params
|
||||
|
||||
params_type = query_params['type']
|
||||
params_type = query_params.get('type')
|
||||
if query_params.get('establishment_type'):
|
||||
params_type = query_params.get('establishment_type')
|
||||
elif query_params.get('product_type'):
|
||||
params_type = query_params.get('product_type')
|
||||
|
||||
if params_type == 'restaurant' and 'toque_number__in' in query_params:
|
||||
week_days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
|
||||
flags = ('toque_number', 'wine_region', 'works_noon', 'works_evening', 'works_now', 'works_at_weekday')
|
||||
filter_flags = {flag_name: False for flag_name in flags}
|
||||
additional_flags = []
|
||||
|
||||
if params_type == 'restaurant':
|
||||
additional_flags += ['toque_number', 'works_noon', 'works_evening', 'works_now']
|
||||
|
||||
elif params_type == 'winery':
|
||||
additional_flags += ['wine_region']
|
||||
|
||||
elif params_type == 'artisan':
|
||||
additional_flags += ['works_now', 'works_at_weekday']
|
||||
|
||||
for flag_name in additional_flags:
|
||||
filter_flags[flag_name] = True
|
||||
|
||||
if filter_flags['toque_number']:
|
||||
toques = {
|
||||
"index_name": "toque_number",
|
||||
"label_translated": "Toques",
|
||||
|
|
@ -93,28 +114,29 @@ class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
|||
}
|
||||
result_list.append(toques)
|
||||
|
||||
if params_type == 'winery' and 'wine_region_id__in' in query_params:
|
||||
try:
|
||||
wine_region_id = int(query_params['wine_region_id__in'])
|
||||
if filter_flags['wine_region']:
|
||||
wine_region_id = query_params.get('wine_region_id__in')
|
||||
|
||||
wine_regions = {
|
||||
"index_name": "wine_region",
|
||||
"label_translated": "Wine region",
|
||||
"param_name": "wine_region_id__in",
|
||||
"filters": [{
|
||||
"id": obj.id,
|
||||
"index_name": obj.name.lower().replace(' ', '_'),
|
||||
"label_translated": obj.name
|
||||
} for obj in WineRegion.objects.filter(id=wine_region_id)]
|
||||
}
|
||||
if str(wine_region_id).isdigit():
|
||||
queryset = WineRegion.objects.filter(id=int(wine_region_id))
|
||||
|
||||
result_list.append(wine_regions)
|
||||
else:
|
||||
queryset = WineRegion.objects.all()
|
||||
|
||||
except ValueError:
|
||||
pass
|
||||
wine_regions = {
|
||||
"index_name": "wine_region",
|
||||
"label_translated": "Wine region",
|
||||
"param_name": "wine_region_id__in",
|
||||
"filters": [{
|
||||
"id": obj.id,
|
||||
"index_name": obj.name.lower().replace(' ', '_'),
|
||||
"label_translated": obj.name
|
||||
} for obj in queryset]
|
||||
}
|
||||
|
||||
if params_type == 'restaurant' and 'works_noon__in' in query_params:
|
||||
week_days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
|
||||
result_list.append(wine_regions)
|
||||
|
||||
if filter_flags['works_noon']:
|
||||
works_noon = {
|
||||
"index_name": "works_noon",
|
||||
"label_translated": "Open noon",
|
||||
|
|
@ -127,8 +149,8 @@ class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
|||
}
|
||||
result_list.append(works_noon)
|
||||
|
||||
if params_type == 'restaurant' and 'works_evening__in' in query_params:
|
||||
week_days = ("Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday")
|
||||
if filter_flags['works_evening']:
|
||||
|
||||
works_evening = {
|
||||
"index_name": "works_evening",
|
||||
"label_translated": "Open evening",
|
||||
|
|
@ -141,7 +163,7 @@ class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
|||
}
|
||||
result_list.append(works_evening)
|
||||
|
||||
if params_type in ('restaurant', 'artisan') and 'works_now' in query_params:
|
||||
if filter_flags['works_now']:
|
||||
works_now = {
|
||||
"index_name": "open_now",
|
||||
"label_translated": "Open now",
|
||||
|
|
@ -150,6 +172,19 @@ class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
|
|||
}
|
||||
result_list.append(works_now)
|
||||
|
||||
if filter_flags['works_at_weekday']:
|
||||
works_at_weekday = {
|
||||
"index_name": "works_at_weekday",
|
||||
"label_translated": "Works at weekday",
|
||||
"param_name": "works_at_weekday__in",
|
||||
"filters": [{
|
||||
"id": weekday,
|
||||
"index_name": week_days[weekday].lower(),
|
||||
"label_translated": week_days[weekday]
|
||||
} for weekday in range(7)]
|
||||
}
|
||||
result_list.append(works_at_weekday)
|
||||
|
||||
if 'tags_id__in' in query_params:
|
||||
# filtering by params_type and tags id
|
||||
# todo: result_list.append( filtering_data )
|
||||
|
|
|
|||
|
|
@ -1224,6 +1224,23 @@ class Footers(MigrateMixin):
|
|||
db_table = 'footers'
|
||||
|
||||
|
||||
class Panels(MigrateMixin):
|
||||
using = 'legacy'
|
||||
|
||||
name = models.CharField(max_length=255, blank=True, null=True)
|
||||
display = models.CharField(max_length=255, blank=True, null=True)
|
||||
description = models.CharField(max_length=255, blank=True, null=True)
|
||||
query = models.TextField(blank=True, null=True)
|
||||
created_at = models.DateTimeField(blank=True, null=True)
|
||||
updated_at = models.DateTimeField(blank=True, null=True)
|
||||
account_id = models.IntegerField(blank=True, null=True)
|
||||
site_id = models.IntegerField(blank=True, null=True)
|
||||
|
||||
class Meta:
|
||||
managed = False
|
||||
db_table = 'panels'
|
||||
|
||||
|
||||
class OwnershipAffs(MigrateMixin):
|
||||
using = 'legacy'
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import logging
|
|||
import random
|
||||
import re
|
||||
import string
|
||||
from collections import namedtuple
|
||||
|
||||
import requests
|
||||
from django.conf import settings
|
||||
|
|
@ -124,3 +125,10 @@ def absolute_url_decorator(func):
|
|||
def get_point_from_coordinates(latitude: str, longitude: str):
|
||||
if latitude and longitude:
|
||||
return Point(x=longitude, y=latitude, srid=4326)
|
||||
|
||||
|
||||
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()]
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@ services:
|
|||
- .:/code
|
||||
|
||||
|
||||
|
||||
|
||||
# PostgreSQL database
|
||||
db:
|
||||
build:
|
||||
|
|
|
|||
|
|
@ -516,9 +516,6 @@ PHONENUMBER_DEFAULT_REGION = "FR"
|
|||
|
||||
FALLBACK_LOCALE = 'en-GB'
|
||||
|
||||
# TMP TODO remove it later
|
||||
# Временный хардкод для демонстрации > 15 ноября, потом удалить!
|
||||
CAROUSEL_ITEMS = [465]
|
||||
ESTABLISHMENT_CHOSEN_TAGS = ['gastronomic', 'en_vogue', 'terrace', 'streetfood', 'business', 'bar_cocktail', 'brunch', 'pop']
|
||||
NEWS_CHOSEN_TAGS = ['eat', 'drink', 'cook', 'style', 'international', 'event', 'partnership']
|
||||
INTERNATIONAL_COUNTRY_CODES = ['www', 'main', 'next']
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user