GM-127: in progress

This commit is contained in:
Anatoly 2019-09-25 19:39:37 +03:00
parent 8766388256
commit 207e35feb1
6 changed files with 44 additions and 35 deletions

View File

@ -1,18 +1,20 @@
"""Establishment models.""" """Establishment models."""
from functools import reduce from functools import reduce
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.measure import Distance as DistanceMeasure from django.conf import settings
from django.contrib.gis.geos import Point
from django.contrib.contenttypes import fields as generic from django.contrib.contenttypes import fields as generic
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import Distance as DistanceMeasure
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.db.models import When, Case, F, ExpressionWrapper, Subquery
from django.utils import timezone from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from phonenumber_field.modelfields import PhoneNumberField from phonenumber_field.modelfields import PhoneNumberField
from location.models import Address
from collection.models import Collection from collection.models import Collection
from location.models import Address
from review.models import Review from review.models import Review
from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, URLImageMixin, from utils.models import (ProjectBaseMixin, ImageMixin, TJSONField, URLImageMixin,
TranslatedFieldsMixin, BaseAttributes) TranslatedFieldsMixin, BaseAttributes)
@ -128,27 +130,28 @@ class EstablishmentQuerySet(models.QuerySet):
output_field=models.FloatField() output_field=models.FloatField()
)) ))
def similar(self, establishment_slug: str, output_objects: int = 12): def similar(self, establishment_slug: str):
""" """
Return QuerySet with objects that similar to Establishment. Return QuerySet with objects that similar to Establishment.
:param establishment_slug: str Establishment slug :param establishment_slug: str Establishment slug
:param output_objects: int of output objects
""" """
establishment_qs = Establishment.objects.filter(slug=establishment_slug, establishment_qs = Establishment.objects.filter(slug=establishment_slug,
public_mark__isnull=False) public_mark__isnull=False)
if establishment_qs.exists(): if establishment_qs.exists():
establishment = establishment_qs.first() establishment = establishment_qs.first()
return self.exclude(slug=establishment_slug) \ subquery_filter_by_distance = Subquery(
.filter(is_publish=True, self.exclude(slug=establishment_slug)
image_url__isnull=False, .filter(image_url__isnull=False, public_mark__gte=10)
reviews__isnull=False, .published()
reviews__status=Review.READY, .has_published_reviews()
public_mark__gte=10) \ .annotate_distance(point=establishment.address.coordinates)
.annotate_distance(point=establishment.address.coordinates) \ .order_by('distance')[:settings.LIMITING_QUERY_NUMBER]
.values('id')
)
return Establishment.objects.filter(id__in=subquery_filter_by_distance) \
.annotate_intermediate_public_mark() \ .annotate_intermediate_public_mark() \
.annotate_mark_similarity(mark=establishment.public_mark) \ .annotate_mark_similarity(mark=establishment.public_mark) \
.order_by('distance') \ .order_by('mark_similarity')
.order_by('mark_similarity')[:output_objects]
else: else:
return self.none() return self.none()

View File

@ -191,7 +191,7 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer):
schedule = ScheduleRUDSerializer(many=True, allow_null=True) schedule = ScheduleRUDSerializer(many=True, allow_null=True)
phones = ContactPhonesSerializer(read_only=True, many=True, ) phones = ContactPhonesSerializer(read_only=True, many=True, )
emails = ContactEmailsSerializer(read_only=True, many=True, ) emails = ContactEmailsSerializer(read_only=True, many=True, )
review = serializers.SerializerMethodField() review = ReviewSerializer(source='last_published_review', allow_null=True)
employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees', employees = EstablishmentEmployeeSerializer(source='actual_establishment_employees',
many=True) many=True)
menu = MenuSerializers(source='menu_set', many=True, read_only=True) menu = MenuSerializers(source='menu_set', many=True, read_only=True)
@ -201,7 +201,7 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer):
slug = serializers.SlugField(required=True, allow_blank=False, max_length=50) slug = serializers.SlugField(required=True, allow_blank=False, max_length=50)
in_favorites = serializers.SerializerMethodField() in_favorites = serializers.BooleanField()
image = serializers.URLField(source='image_url') image = serializers.URLField(source='image_url')
@ -231,21 +231,6 @@ class EstablishmentDetailSerializer(EstablishmentListSerializer):
'slug', 'slug',
] ]
def get_review(self, obj):
"""Serializer method for getting last published review"""
return ReviewSerializer(obj.reviews.by_status(status=review_models.Review.READY)
.order_by('-published_at').first()).data
def get_in_favorites(self, obj):
"""Get in_favorites status flag"""
user = self.context.get('request').user
if user.is_authenticated:
return obj.id in user.favorites.by_content_type(app_label='establishment',
model='establishment')\
.values_list('object_id', flat=True)
else:
return False
class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer): class EstablishmentCommentCreateSerializer(comment_serializers.CommentSerializer):
"""Create comment serializer""" """Create comment serializer"""

View File

@ -9,6 +9,7 @@ from establishment import filters
from establishment import models, serializers from establishment import models, serializers
from establishment.views import EstablishmentMixin from establishment.views import EstablishmentMixin
from main.models import MetaDataContent from main.models import MetaDataContent
from utils.pagination import EstablishmentPagination
from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer from timetable.serialziers import ScheduleRUDSerializer, ScheduleCreateSerializer
@ -27,10 +28,12 @@ class EstablishmentListView(EstablishmentMixin, generics.ListAPIView):
class EstablishmentSimilarListView(EstablishmentListView): class EstablishmentSimilarListView(EstablishmentListView):
"""Resource for getting a list of establishments.""" """Resource for getting a list of establishments."""
serializer_class = serializers.EstablishmentListSerializer serializer_class = serializers.EstablishmentListSerializer
pagination_class = EstablishmentPagination
def get_queryset(self): def get_queryset(self):
"""Override get_queryset method""" """Override get_queryset method"""
return super().get_queryset().similar(establishment_slug=self.kwargs.get('slug')) return super().get_queryset() \
.similar(establishment_slug=self.kwargs.get('slug'))
class EstablishmentRetrieveView(EstablishmentMixin, generics.RetrieveAPIView): class EstablishmentRetrieveView(EstablishmentMixin, generics.RetrieveAPIView):
@ -38,6 +41,11 @@ class EstablishmentRetrieveView(EstablishmentMixin, generics.RetrieveAPIView):
lookup_field = 'slug' lookup_field = 'slug'
serializer_class = serializers.EstablishmentDetailSerializer serializer_class = serializers.EstablishmentDetailSerializer
def get_queryset(self):
"""Override 'get_queryset' method."""
return super(EstablishmentRetrieveView, self).get_queryset() \
.annotate_in_favorites(self.request.user)
class EstablishmentTypeListView(generics.ListAPIView): class EstablishmentTypeListView(generics.ListAPIView):
"""Resource for getting a list of establishment types.""" """Resource for getting a list of establishment types."""

View File

@ -23,6 +23,10 @@ class ReviewQuerySet(models.QuerySet):
"""Filter by status""" """Filter by status"""
return self.filter(status=status) return self.filter(status=status)
def published(self):
"""Return published reviews"""
return self.filter(status=Review.READY)
class Review(BaseAttributes, TranslatedFieldsMixin): class Review(BaseAttributes, TranslatedFieldsMixin):
"""Review model""" """Review model"""

View File

@ -44,3 +44,10 @@ class ProjectMobilePagination(ProjectPageNumberPagination):
if not self.page.has_previous(): if not self.page.has_previous():
return None return None
return self.page.previous_page_number() return self.page.previous_page_number()
class EstablishmentPagination(ProjectMobilePagination):
"""
Pagination for app establishments with limit page size equal to 12
"""
page_size = 12

View File

@ -412,3 +412,5 @@ SOLO_CACHE_TIMEOUT = 300
SITE_REDIRECT_URL_UNSUBSCRIBE = '/unsubscribe/' SITE_REDIRECT_URL_UNSUBSCRIBE = '/unsubscribe/'
SITE_NAME = 'Gault & Millau' SITE_NAME = 'Gault & Millau'
LIMITING_QUERY_NUMBER = 36 # Need to restrict objects to sort (used in establishments)