intermediate commit

This commit is contained in:
Anatoly 2019-12-23 12:38:13 +03:00
parent f87d891daa
commit 7452f0bef0
11 changed files with 123 additions and 15 deletions

View File

@ -568,6 +568,10 @@ class GuideElementQuerySet(models.QuerySet):
"""Return GuideElement with type WineNode.""" """Return GuideElement with type WineNode."""
return self.filter(guide_element_type__name='WineNode') return self.filter(guide_element_type__name='WineNode')
def descendants(self):
"""Return QuerySet with descendants."""
return self.exclude(guide_element_type__name='Root')
class GuideElement(ProjectBaseMixin, MPTTModel): class GuideElement(ProjectBaseMixin, MPTTModel):
"""Frozen state of elements of guide instance.""" """Frozen state of elements of guide instance."""

View File

@ -4,6 +4,9 @@ from collection import models
from location import models as location_models from location import models as location_models
from main.serializers import SiteShortSerializer from main.serializers import SiteShortSerializer
from utils.serializers import TranslatedField from utils.serializers import TranslatedField
from rest_framework_recursive.fields import RecursiveField
from establishment.serializers import EstablishmentGuideElementSerializer
from product.serializers import ProductGuideElementSerializer
class CollectionBaseSerializer(serializers.ModelSerializer): class CollectionBaseSerializer(serializers.ModelSerializer):
@ -94,7 +97,8 @@ class GuideBaseSerializer(serializers.ModelSerializer):
restaurant_counter = serializers.IntegerField(read_only=True) restaurant_counter = serializers.IntegerField(read_only=True)
shop_counter = serializers.IntegerField(read_only=True) shop_counter = serializers.IntegerField(read_only=True)
wine_counter = serializers.IntegerField(read_only=True) wine_counter = serializers.IntegerField(read_only=True)
present_objects_counter = serializers.IntegerField(read_only=True) count_objects_during_init = serializers.IntegerField(read_only=True,
source='count_related_objects')
class Meta: class Meta:
model = models.Guide model = models.Guide
@ -115,7 +119,6 @@ class GuideBaseSerializer(serializers.ModelSerializer):
'restaurant_counter', 'restaurant_counter',
'shop_counter', 'shop_counter',
'wine_counter', 'wine_counter',
'present_objects_counter',
'count_objects_during_init', 'count_objects_during_init',
] ]
extra_kwargs = { extra_kwargs = {
@ -166,3 +169,36 @@ class GuideFilterBaseSerializer(serializers.ModelSerializer):
"""Overridden create method.""" """Overridden create method."""
validated_data['guide'] = self.get_guide(validated_data.pop('guide', None)) validated_data['guide'] = self.get_guide(validated_data.pop('guide', None))
return super().create(validated_data) return super().create(validated_data)
class GuideElementBaseSerializer(serializers.ModelSerializer):
"""Serializer for model GuideElement."""
establishment_detail = EstablishmentGuideElementSerializer(read_only=True,
source='establishment')
section_name = serializers.CharField(source='section.name',
allow_null=True)
wine_color_section_name = serializers.CharField(source='wine_color_section.name',
allow_null=True)
node_name = serializers.CharField(source='guide_element_type.name')
label_photo = serializers.ImageField(source='label_photo.image', allow_null=True)
city_name = serializers.CharField(source='city.name', allow_null=True)
product_detail = ProductGuideElementSerializer(read_only=True, source='product')
parent = RecursiveField(required=False)
class Meta:
"""Meta class."""
model = models.GuideElement
fields = [
'node_name',
'establishment_detail',
'review',
'wine_region',
'product_detail',
'priority',
'city_name',
'section_name',
'wine_color_section_name',
'parent',
'label_photo',
]

View File

@ -12,8 +12,8 @@ router.register(r'collections', views.CollectionBackOfficeViewSet)
urlpatterns = [ urlpatterns = [
path('guides/', views.GuideListCreateView.as_view(), path('guides/', views.GuideListCreateView.as_view(),
name='guide-list-create'), name='guide-list-create'),
# path('guides/<int:pk>/elements/', views.GuideElementListView.as_view(), path('guides/<int:pk>/', views.GuideElementListView.as_view(),
# name='guide-element-list'), name='guide-element-list'),
path('guides/<int:pk>/filters/', views.GuideFilterCreateView.as_view(), path('guides/<int:pk>/filters/', views.GuideFilterCreateView.as_view(),
name='guide-filter-list-create'), name='guide-filter-list-create'),
] + router.urls ] + router.urls

View File

@ -4,6 +4,7 @@ from rest_framework import mixins, permissions, viewsets
from rest_framework import status from rest_framework import status
from rest_framework.filters import OrderingFilter from rest_framework.filters import OrderingFilter
from rest_framework.response import Response from rest_framework.response import Response
from django.shortcuts import get_object_or_404
from collection import models, serializers from collection import models, serializers
from utils.views import BindObjectMixin from utils.views import BindObjectMixin
@ -27,7 +28,7 @@ class CollectionViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
class GuideBaseView(generics.GenericAPIView): class GuideBaseView(generics.GenericAPIView):
"""ViewSet for Guide model.""" """ViewSet for Guide model."""
serializer_class = serializers.GuideBaseSerializer serializer_class = serializers.GuideBaseSerializer
permission_classes = (permissions.IsAuthenticated, ) permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def get_queryset(self): def get_queryset(self):
"""Overridden get_queryset method.""" """Overridden get_queryset method."""
@ -43,7 +44,15 @@ class GuideFilterBaseView(generics.GenericAPIView):
pagination_class = None pagination_class = None
queryset = models.GuideFilter.objects.all() queryset = models.GuideFilter.objects.all()
serializer_class = serializers.GuideFilterBaseSerializer serializer_class = serializers.GuideFilterBaseSerializer
permission_classes = (permissions.IsAuthenticated,) permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class GuideElementBaseView(generics.GenericAPIView):
"""Base view for GuideElement model."""
pagination_class = None
queryset = models.GuideElement.objects.all()
serializer_class = serializers.GuideElementBaseSerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
class CollectionBackOfficeViewSet(mixins.CreateModelMixin, class CollectionBackOfficeViewSet(mixins.CreateModelMixin,
@ -98,3 +107,14 @@ class GuideFilterCreateView(GuideFilterBaseView,
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
super().create(request, *args, **kwargs) super().create(request, *args, **kwargs)
return Response(status=status.HTTP_200_OK) return Response(status=status.HTTP_200_OK)
class GuideElementListView(GuideElementBaseView,
generics.ListAPIView):
"""View for model GuideElement for back office users."""
def get_queryset(self):
"""Overridden get_queryset method."""
guide = get_object_or_404(models.Guide.objects.all(), pk=self.kwargs.get('pk'))
return models.GuideElement.objects.get_root_node(guide) \
.get_descendants()

View File

@ -244,8 +244,9 @@ class EstablishmentQuerySet(models.QuerySet):
return Subquery( return Subquery(
self.similar_base(establishment) self.similar_base(establishment)
.filter(**filters) .filter(**filters)
.order_by('distance')[:settings.LIMITING_QUERY_OBJECTS] .order_by('distance')
.values('id') .distinct()
.values_list('id', flat=True)[:settings.LIMITING_QUERY_OBJECTS]
) )
def similar_restaurants(self, slug): def similar_restaurants(self, slug):
@ -263,7 +264,8 @@ class EstablishmentQuerySet(models.QuerySet):
'establishment_gallery__is_main': True, 'establishment_gallery__is_main': True,
} }
) )
return self.filter(id__in=ids_by_subquery) \ # todo: fix this - replace ids_by_subquery.queryset on ids_by_subquery
return self.filter(id__in=ids_by_subquery.queryset) \
.annotate_intermediate_public_mark() \ .annotate_intermediate_public_mark() \
.annotate_mark_similarity(mark=restaurant.public_mark) \ .annotate_mark_similarity(mark=restaurant.public_mark) \
.order_by('mark_similarity') \ .order_by('mark_similarity') \

View File

@ -621,3 +621,33 @@ class CompanyBaseSerializer(serializers.ModelSerializer):
if models.Company.objects.filter(phones__overlap=phones).exists(): if models.Company.objects.filter(phones__overlap=phones).exists():
raise serializers.ValidationError({'detail': _('Phones is already reserved.')}) raise serializers.ValidationError({'detail': _('Phones is already reserved.')})
return attrs return attrs
class EstablishmentGuideElementSerializer(serializers.ModelSerializer):
"""Serializer for Guide serializer."""
type = EstablishmentTypeBaseSerializer(source='establishment_type', read_only=True)
subtypes = EstablishmentSubTypeBaseSerializer(many=True, source='establishment_subtypes')
address = AddressBaseSerializer()
tz = serializers.CharField(read_only=True, source='timezone_as_str')
schedule = ScheduleRUDSerializer(many=True, allow_null=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)
range_price_menu = RangePriceSerializer(read_only=True)
range_price_carte = RangePriceSerializer(read_only=True)
currency = CurrencySerializer()
class Meta(EstablishmentBaseSerializer.Meta):
"""Meta class."""
fields = [
'id',
'type',
'subtypes',
'address',
'tz',
'schedule',
'best_price_menu',
'best_price_carte',
'range_price_menu',
'range_price_carte',
'currency',
]

View File

@ -44,7 +44,7 @@ class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView):
class EstablishmentSimilarView(EstablishmentListView): class EstablishmentSimilarView(EstablishmentListView):
"""Resource for getting a list of similar establishments.""" """Resource for getting a list of similar establishments."""
serializer_class = serializers.EstablishmentSimilarSerializer serializer_class = serializers.EstablishmentSimilarSerializer
pagination_class = PortionPagination pagination_class = None
class EstablishmentRetrieveView(EstablishmentMixinView, generics.RetrieveAPIView): class EstablishmentRetrieveView(EstablishmentMixinView, generics.RetrieveAPIView):
@ -90,7 +90,7 @@ class RestaurantSimilarListView(EstablishmentSimilarView):
"""Overridden get_queryset method""" """Overridden get_queryset method"""
return EstablishmentMixinView.get_queryset(self) \ return EstablishmentMixinView.get_queryset(self) \
.has_location() \ .has_location() \
.similar_restaurants(slug=self.kwargs.get('slug')) .similar_restaurants(slug=self.kwargs.get('slug'))[:settings.QUERY_OUTPUT_OBJECTS]
class WinerySimilarListView(EstablishmentSimilarView): class WinerySimilarListView(EstablishmentSimilarView):
@ -100,7 +100,7 @@ class WinerySimilarListView(EstablishmentSimilarView):
"""Overridden get_queryset method""" """Overridden get_queryset method"""
return EstablishmentMixinView.get_queryset(self) \ return EstablishmentMixinView.get_queryset(self) \
.has_location() \ .has_location() \
.similar_wineries(slug=self.kwargs.get('slug')) .similar_wineries(slug=self.kwargs.get('slug'))[:settings.QUERY_OUTPUT_OBJECTS]
class ArtisanProducerSimilarListView(EstablishmentSimilarView): class ArtisanProducerSimilarListView(EstablishmentSimilarView):
@ -110,7 +110,7 @@ class ArtisanProducerSimilarListView(EstablishmentSimilarView):
"""Overridden get_queryset method""" """Overridden get_queryset method"""
return EstablishmentMixinView.get_queryset(self) \ return EstablishmentMixinView.get_queryset(self) \
.has_location() \ .has_location() \
.similar_artisans_producers(slug=self.kwargs.get('slug')) .similar_artisans_producers(slug=self.kwargs.get('slug'))[:settings.QUERY_OUTPUT_OBJECTS]
class EstablishmentTypeListView(generics.ListAPIView): class EstablishmentTypeListView(generics.ListAPIView):

View File

@ -219,3 +219,15 @@ class ProductCommentCreateSerializer(CommentSerializer):
'content_object': validated_data.pop('product') 'content_object': validated_data.pop('product')
}) })
return super().create(validated_data) return super().create(validated_data)
class ProductGuideElementSerializer(ProductBaseSerializer):
"""Serializer for serializing in GuideElement for model Product."""
class Meta(ProductBaseSerializer.Meta):
"""Meta class."""
_unused_fields = ('tags', 'wine_regions', 'wine_colors', 'preview_image_url')
fields = ProductBaseSerializer.Meta.fields
# pop unused fields
for unused_field in _unused_fields: fields.pop(fields.index(unused_field))

View File

@ -7,6 +7,7 @@ from product import filters, serializers
from comment.serializers import CommentRUDSerializer from comment.serializers import CommentRUDSerializer
from utils.views import FavoritesCreateDestroyMixinView from utils.views import FavoritesCreateDestroyMixinView
from utils.pagination import PortionPagination from utils.pagination import PortionPagination
from django.conf import settings
class ProductBaseView(generics.GenericAPIView): class ProductBaseView(generics.GenericAPIView):
@ -97,5 +98,5 @@ class SimilarListView(ProductSimilarView):
"""Overridden get_queryset method.""" """Overridden get_queryset method."""
return super().get_queryset() \ return super().get_queryset() \
.has_location() \ .has_location() \
.similar(slug=self.kwargs.get('slug')) .similar(slug=self.kwargs.get('slug'))[:settings.QUERY_OUTPUT_OBJECTS]

View File

@ -72,7 +72,7 @@ class TimeZoneChoiceField(serializers.ChoiceField):
class ProjectModelSerializer(serializers.ModelSerializer): class ProjectModelSerializer(serializers.ModelSerializer):
"""Overrided ModelSerializer.""" """Overridden ModelSerializer."""
serializers.ModelSerializer.serializer_field_mapping[models.TJSONField] = TJSONField serializers.ModelSerializer.serializer_field_mapping[models.TJSONField] = TJSONField

View File

@ -63,3 +63,6 @@ pycountry==19.8.18
# sql-tree # sql-tree
django-mptt==0.9.1 django-mptt==0.9.1
# For recursive fields
djangorestframework-recursive==0.1.2