Merge branch 'develop' into feature/fix-country-region-city-transfer

This commit is contained in:
littlewolf 2019-12-13 09:18:44 +03:00
commit 6ef0e7adfe
23 changed files with 445 additions and 69 deletions

View File

@ -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,

View File

@ -213,7 +213,13 @@ class EstablishmentQuerySet(models.QuerySet):
))
def similar_base(self, establishment):
"""
Return filtered QuerySet by base filters.
Filters including:
1 Filter by type (and subtype) establishment.
2 Filter by published Review.
3 With annotated distance.
"""
filters = {
'reviews__status': Review.READY,
'establishment_type': establishment.establishment_type,
@ -224,27 +230,64 @@ class EstablishmentQuerySet(models.QuerySet):
.filter(**filters) \
.annotate_distance(point=establishment.location)
def similar_base_subquery(self, establishment, filters: dict) -> Subquery:
"""
Return filtered Subquery object by filters.
Filters including:
1 Filter by transmitted filters.
2 With ordering by distance.
"""
return Subquery(
self.similar_base(establishment)
.filter(**filters)
.order_by('distance')[:settings.LIMITING_QUERY_OBJECTS]
.values('id')
)
def similar_restaurants(self, slug):
"""
Return QuerySet with objects that similar to Restaurant.
:param restaurant_slug: str Establishment slug
:param slug: str restaurant slug
"""
restaurant_qs = self.filter(slug=slug,
public_mark__isnull=False)
restaurant_qs = self.filter(slug=slug)
if restaurant_qs.exists():
establishment = restaurant_qs.first()
subquery_filter_by_distance = Subquery(
self.similar_base(establishment)
.filter(public_mark__gte=10,
establishment_gallery__is_main=True)
.order_by('distance')[:settings.LIMITING_QUERY_OBJECTS]
.values('id')
restaurant = restaurant_qs.first()
ids_by_subquery = self.similar_base_subquery(
establishment=restaurant,
filters={
'public_mark__gte': 10,
'establishment_gallery__is_main': True,
}
)
return self.filter(id__in=subquery_filter_by_distance) \
return self.filter(id__in=ids_by_subquery) \
.annotate_intermediate_public_mark() \
.annotate_mark_similarity(mark=establishment.public_mark) \
.annotate_mark_similarity(mark=restaurant.public_mark) \
.order_by('mark_similarity') \
.distinct('mark_similarity', 'id')
else:
return self.none()
def similar_artisans(self, slug):
"""
Return QuerySet with objects that similar to Artisan.
:param slug: str artisan slug
"""
artisan_qs = self.filter(slug=slug)
if artisan_qs.exists():
artisan = artisan_qs.first()
ids_by_subquery = self.similar_base_subquery(
establishment=artisan,
filters={
'public_mark__gte': 10,
}
)
return self.filter(id__in=ids_by_subquery) \
.annotate_intermediate_public_mark() \
.annotate_mark_similarity(mark=artisan.public_mark) \
.order_by('mark_similarity') \
.distinct('mark_similarity', 'id')
else:
return self.none()
def by_wine_region(self, wine_region):
"""

View File

@ -21,6 +21,8 @@ urlpatterns = [
path('slug/<slug:slug>/similar/', views.RestaurantSimilarListView.as_view(),
name='similar-restaurants'),
path('slug/<slug:slug>/similar/wineries/', views.WinerySimilarListView.as_view(),
name='similar-restaurants'),
name='similar-wineries'),
path('slug/<slug:slug>/similar/artisans/', views.ArtisanSimilarListView.as_view(),
name='similar-artisans'),
]

View File

@ -1,6 +1,7 @@
"""Establishment app views."""
from django.http import Http404, HttpResponse
from django.shortcuts import get_object_or_404
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import generics, permissions, status
from establishment import filters, models, serializers
@ -41,7 +42,7 @@ class EstablishmentScheduleRUDView(generics.RetrieveUpdateDestroyAPIView):
"""Establishment schedule RUD view"""
lookup_field = 'slug'
serializer_class = ScheduleRUDSerializer
permission_classes = [IsWineryReviewer |IsEstablishmentManager]
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
def get_object(self):
"""
@ -75,6 +76,11 @@ class MenuListCreateView(generics.ListCreateAPIView):
serializer_class = serializers.MenuSerializers
queryset = models.Menu.objects.all()
permission_classes = [IsWineryReviewer | IsEstablishmentManager]
filter_backends = (DjangoFilterBackend,)
filterset_fields = (
'establishment',
'establishment__slug',
)
class MenuRUDView(generics.RetrieveUpdateDestroyAPIView):
@ -161,7 +167,7 @@ class EmailRUDView(generics.RetrieveUpdateDestroyAPIView):
class EmployeeListCreateView(generics.ListCreateAPIView):
"""Emplyoee list create view."""
permission_classes = (permissions.AllowAny, )
permission_classes = (permissions.AllowAny,)
filter_class = filters.EmployeeBackFilter
serializer_class = serializers.EmployeeBackSerializers
queryset = models.Employee.objects.all()
@ -170,7 +176,7 @@ class EmployeeListCreateView(generics.ListCreateAPIView):
class EstablishmentEmployeeListView(generics.ListCreateAPIView):
"""Establishment emplyoees list view."""
permission_classes = (permissions.AllowAny, )
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.EstablishmentEmployeeBackSerializer
def get_queryset(self):
@ -352,8 +358,8 @@ class EstablishmentEmployeeCreateView(generics.CreateAPIView):
class EstablishmentEmployeeDeleteView(generics.DestroyAPIView):
def _get_object_to_delete(self, establishment_id, employee_id):
result_qs = models.EstablishmentEmployee\
.objects\
result_qs = models.EstablishmentEmployee \
.objects \
.filter(establishment_id=establishment_id, employee_id=employee_id)
if not result_qs.exists():
raise Http404
@ -371,6 +377,6 @@ class EstablishmentPositionListView(generics.ListAPIView):
"""Establishment positions list view."""
pagination_class = None
permission_classes = (permissions.AllowAny, )
permission_classes = (permissions.AllowAny,)
queryset = models.Position.objects.all()
serializer_class = serializers.PositionBackSerializer

View File

@ -87,7 +87,7 @@ class RestaurantSimilarListView(EstablishmentSimilarList):
"""Resource for getting a list of similar restaurants."""
def get_queryset(self):
"""Override get_queryset method"""
"""Overridden get_queryset method"""
return EstablishmentMixinView.get_queryset(self) \
.similar_restaurants(slug=self.kwargs.get('slug'))
@ -96,11 +96,20 @@ class WinerySimilarListView(EstablishmentSimilarList):
"""Resource for getting a list of similar wineries."""
def get_queryset(self):
"""Override get_queryset method"""
"""Overridden get_queryset method"""
return EstablishmentMixinView.get_queryset(self) \
.similar_wineries(slug=self.kwargs.get('slug'))
class ArtisanSimilarListView(EstablishmentSimilarList):
"""Resource for getting a list of similar artisans."""
def get_queryset(self):
"""Overridden get_queryset method"""
return EstablishmentMixinView.get_queryset(self) \
.similar_artisans(slug=self.kwargs.get('slug'))
class EstablishmentTypeListView(generics.ListAPIView):
"""Resource for getting a list of establishment types."""

View 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.'))

View 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',
},
),
]

View File

@ -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

View File

@ -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'
]

View File

@ -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')
]

View File

@ -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()

View File

@ -0,0 +1,18 @@
# Generated by Django 2.2.7 on 2019-12-12 13:47
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('news', '0041_auto_20191211_1528'),
]
operations = [
migrations.AddField(
model_name='news',
name='duplication_date',
field=models.DateTimeField(blank=True, default=None, null=True, verbose_name='Duplication datetime'),
),
]

View File

@ -211,6 +211,8 @@ class News(GalleryModelMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixi
verbose_name=_('banner'))
site = models.ForeignKey('main.SiteSettings', blank=True, null=True,
on_delete=models.SET_NULL, verbose_name=_('site settings'))
duplication_date = models.DateTimeField(blank=True, null=True, default=None,
verbose_name=_('Duplication datetime'))
objects = NewsQuerySet.as_manager()
class Meta:
@ -220,7 +222,16 @@ class News(GalleryModelMixin, BaseAttributes, TranslatedFieldsMixin, HasTagsMixi
verbose_name_plural = _('news')
def __str__(self):
return f'news: {self.slug}'
return f'news: {next(iter(self.slugs.values()))}'
def create_duplicate(self, new_country, view_count_model):
self.pk = None
self.state = self.WAITING
self.slugs = {locale: f'{slug}-{new_country.code}' for locale, slug in self.slugs.items()}
self.country = new_country
self.views_count = view_count_model
self.duplication_date = timezone.now()
self.save()
@property
def is_publish(self):

View File

@ -13,6 +13,9 @@ from tag.serializers import TagBaseSerializer
from utils import exceptions as utils_exceptions
from utils.serializers import (TranslatedField, ProjectModelSerializer,
FavoritesCreateSerializer, ImageBaseSerializer, CarouselCreateSerializer)
from rating import models as rating_models
from django.shortcuts import get_object_or_404
from utils.models import get_current_locale, get_default_locale
class AgendaSerializer(ProjectModelSerializer):
@ -68,6 +71,13 @@ class NewsBaseSerializer(ProjectModelSerializer):
tags = TagBaseSerializer(read_only=True, many=True, source='visible_tags')
in_favorites = serializers.BooleanField(allow_null=True, read_only=True)
view_counter = serializers.IntegerField(read_only=True)
slug = serializers.SerializerMethodField(read_only=True, allow_null=True)
def get_slug(self, obj):
if obj.slugs:
return obj.slugs.get(get_current_locale()) \
or obj.slugs.get(get_default_locale()) \
or next(iter(obj.slugs.values()))
class Meta:
"""Meta class."""
@ -75,12 +85,12 @@ class NewsBaseSerializer(ProjectModelSerializer):
model = models.News
fields = (
'id',
'slug',
'title_translated',
'subtitle_translated',
'is_highlighted',
'news_type',
'tags',
'slugs',
'view_counter',
)
@ -171,10 +181,13 @@ class NewsBackOfficeBaseSerializer(NewsBaseSerializer):
'title',
'backoffice_title',
'subtitle',
'slugs',
'is_published',
'duplication_date',
)
extra_kwargs = {
'backoffice_title': {'allow_null': False},
'duplication_date': {'read_only': True},
}
def create(self, validated_data):
@ -327,3 +340,24 @@ class NewsCarouselCreateSerializer(CarouselCreateSerializer):
'content_object': validated_data.pop('news')
})
return super().create(validated_data)
class NewsCloneCreateSerializer(NewsBackOfficeBaseSerializer,
NewsDetailSerializer):
"""Serializer for creating news clone."""
template_display = serializers.CharField(source='get_template_display',
read_only=True)
class Meta(NewsBackOfficeBaseSerializer.Meta, NewsDetailSerializer.Meta):
fields = NewsBackOfficeBaseSerializer.Meta.fields + NewsDetailSerializer.Meta.fields + (
'template_display',
)
read_only_fields = fields
def create(self, validated_data):
kwargs = self.context.get('request').parser_context.get('kwargs')
instance = get_object_or_404(models.News, pk=kwargs['pk'])
new_country = get_object_or_404(location_models.Country, code=kwargs['country_code'])
view_count_model = rating_models.ViewCount.objects.create(count=0)
instance.create_duplicate(new_country, view_count_model)
return instance

View File

@ -14,4 +14,5 @@ urlpatterns = [
path('<int:pk>/gallery/<int:image_id>/', views.NewsBackOfficeGalleryCreateDestroyView.as_view(),
name='gallery-create-destroy'),
path('<int:pk>/carousels/', views.NewsCarouselCreateDestroyView.as_view(), name='create-destroy-carousels'),
path('<int:pk>/clone/<str:country_code>', views.NewsCloneView.as_view(), name='create-destroy-carousels'),
]

View File

@ -7,7 +7,7 @@ from news import filters, models, serializers
from rating.tasks import add_rating
from utils.permissions import IsCountryAdmin, IsContentPageManager
from utils.views import CreateDestroyGalleryViewMixin, FavoritesCreateDestroyMixinView, CarouselCreateDestroyMixinView
from utils.serializers import ImageBaseSerializer
from utils.serializers import ImageBaseSerializer, EmptySerializer
class NewsMixinView:
@ -167,3 +167,10 @@ class NewsCarouselCreateDestroyView(CarouselCreateDestroyMixinView):
_model = models.News
serializer_class = serializers.NewsCarouselCreateSerializer
class NewsCloneView(generics.CreateAPIView):
"""View for creating clone News"""
permission_classes = (permissions.AllowAny, )
serializer_class = serializers.NewsCloneCreateSerializer
queryset = models.News.objects.all()

View 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'),
),
]

View File

@ -222,6 +222,7 @@ class NewsDocumentSerializer(InFavoritesMixin, DocumentSerializer):
subtitle_translated = serializers.SerializerMethodField(allow_null=True)
news_type = NewsTypeSerializer()
tags = TagsDocumentSerializer(many=True, source='visible_tags')
slug = serializers.SerializerMethodField(allow_null=True)
class Meta:
"""Meta class."""
@ -237,9 +238,13 @@ class NewsDocumentSerializer(InFavoritesMixin, DocumentSerializer):
'news_type',
'tags',
'start',
'slugs',
'slug',
)
@staticmethod
def get_slug(obj):
return get_translated_value(obj.slugs)
@staticmethod
def get_title_translated(obj):
return get_translated_value(obj.title)

View File

@ -3,7 +3,6 @@ from rest_framework import permissions
from django_elasticsearch_dsl_drf import constants
from django_elasticsearch_dsl_drf.filter_backends import (
FilteringFilterBackend,
GeoSpatialFilteringFilterBackend,
GeoSpatialOrderingFilterBackend,
OrderingFilterBackend,
)
@ -13,9 +12,24 @@ from search_indexes import serializers, filters, utils
from search_indexes.documents import EstablishmentDocument, NewsDocument
from search_indexes.documents.product import ProductDocument
from utils.pagination import ESDocumentPagination
from tag.models import TagCategory
class NewsDocumentViewSet(BaseDocumentViewSet):
class CustomBaseDocumentViewSet(BaseDocumentViewSet):
def __init__(self, *args, **kwargs):
if self.filter_fields:
for name in TagCategory.objects.all().values('index_name'):
self.filter_fields.update({
f'{name["index_name"]}_id': {
'field': 'tags.id',
'lookups': [constants.LOOKUP_QUERY_IN]
}
})
super().__init__(*args, **kwargs)
class NewsDocumentViewSet(CustomBaseDocumentViewSet):
"""News document ViewSet."""
document = NewsDocument
@ -94,7 +108,7 @@ class MobileNewsDocumentViewSet(NewsDocumentViewSet):
]
class EstablishmentDocumentViewSet(BaseDocumentViewSet):
class EstablishmentDocumentViewSet(CustomBaseDocumentViewSet):
"""Establishment document ViewSet."""
document = EstablishmentDocument
@ -319,7 +333,7 @@ class MobileEstablishmentDocumentViewSet(EstablishmentDocumentViewSet):
]
class ProductDocumentViewSet(BaseDocumentViewSet):
class ProductDocumentViewSet(CustomBaseDocumentViewSet):
"""Product document ViewSet."""
document = ProductDocument

View File

@ -123,19 +123,7 @@ class FiltersTagCategoryBaseSerializer(serializers.ModelSerializer):
return obj in ['open_now', ]
def get_param_name(self, obj):
if obj == 'service':
return 'tags_id__in'
elif obj == 'pop':
return 'tags_id__in'
elif obj == 'open_now':
return 'open_now'
elif obj == 'wine_region':
return 'wine_region_id__in'
return '%s__in' % obj.index_name
return f'{obj.index_name}_id__in'
def get_fields(self, *args, **kwargs):
fields = super(FiltersTagCategoryBaseSerializer, self).get_fields()

View File

@ -1,17 +1,15 @@
"""Tag views."""
from django.conf import settings
from rest_framework import generics
from rest_framework import mixins
from rest_framework import permissions
from rest_framework import status
from rest_framework import viewsets
from rest_framework import generics, mixins, permissions, status, viewsets
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.serializers import ValidationError
from django.utils.translation import gettext_lazy as _
from search_indexes import views as search_views
from location.models import WineRegion
from tag import filters
from tag import models
from tag import serializers
from product.models import ProductType
from tag import filters, models, serializers
class ChosenTagsView(generics.ListAPIView, viewsets.GenericViewSet):
@ -61,14 +59,9 @@ class TagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
# User`s views & viewsets
class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
class FiltersTagCategoryViewSet(TagCategoryViewSet):
"""ViewSet for TagCategory model."""
filterset_class = filters.TagCategoryFilterSet
pagination_class = None
permission_classes = (permissions.AllowAny,)
queryset = models.TagCategory.objects.with_tags().with_base_related(). \
distinct()
serializer_class = serializers.FiltersTagCategoryBaseSerializer
def list(self, request, *args, **kwargs):
@ -92,7 +85,7 @@ class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
if params_type == 'restaurant':
additional_flags += ['toque_number', 'works_noon', 'works_evening', 'works_now']
elif params_type == 'winery':
elif params_type in ['winery', 'wine']:
additional_flags += ['wine_region']
elif params_type == 'artisan':
@ -114,7 +107,7 @@ class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
}
result_list.append(toques)
if filter_flags['wine_region']:
if request.query_params.get('product_type') == ProductType.WINE:
wine_region_id = query_params.get('wine_region_id__in')
if str(wine_region_id).isdigit():
@ -185,12 +178,42 @@ class FiltersTagCategoryViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
}
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 )
pass
search_view_class = self.define_search_view_by_request(request)
facets = search_view_class.as_view({'get': 'list'})(self.mutate_request(self.request)).data['facets']
return Response(self.remove_empty_filters(result_list, facets))
return Response(result_list)
@staticmethod
def mutate_request(request):
"""Remove all filtering get params and remove s_ from the rest of them"""
request.GET._mutable = True
for name in request.query_params.copy().keys():
value = request.query_params.pop(name)
if name.startswith('s_'):
request.query_params[name[2:]] = value[0]
request.GET._mutable = False
return request._request
@staticmethod
def define_search_view_by_request(request):
request.GET._mutable = True
if request.query_params.get('items'):
items = request.query_params.pop('items')[0]
else:
raise ValidationError({'detail': _('Missing required "items" parameter')})
item_to_class = {
'news': search_views.NewsDocumentViewSet,
'establishments': search_views.EstablishmentDocumentViewSet,
'products': search_views.ProductDocumentViewSet,
}
klass = item_to_class.get(items)
if klass is None:
raise ValidationError({'detail': _('news/establishments/products')})
request.GET._mutable = False
return klass
@staticmethod
def remove_empty_filters(filters, facets):
return filters
# BackOffice user`s views & viewsets

View File

@ -1222,3 +1222,20 @@ class Footers(MigrateMixin):
class Meta:
managed = False
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'

View File

@ -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()]