diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 3cdef691..fe9ad53b 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -24,8 +24,8 @@ from collection.models import Collection from location.models import Address from location.models import WineOriginAddressMixin from main.models import Award, Currency -from tag.models import Tag from review.models import Review +from tag.models import Tag from utils.models import (ProjectBaseMixin, TJSONField, URLImageMixin, TranslatedFieldsMixin, BaseAttributes, GalleryModelMixin, IntermediateGalleryModelMixin, HasTagsMixin, @@ -209,23 +209,34 @@ class EstablishmentQuerySet(models.QuerySet): """ return self.annotate(mark_similarity=ExpressionWrapper( mark - F('intermediate_public_mark'), - output_field=models.FloatField() + output_field=models.FloatField(default=0) )) - def similar(self, establishment_slug: str): + def similar_base(self, establishment): + + filters = { + 'reviews__status': Review.READY, + 'establishment_type': establishment.establishment_type, + } + if establishment.establishment_subtypes.exists(): + filters.update({'establishment_subtypes__in': establishment.establishment_subtypes.all()}) + return self.exclude(id=establishment.id) \ + .filter(**filters) \ + .annotate_distance(point=establishment.location) + + def similar_restaurants(self, restaurant_slug): """ - Return QuerySet with objects that similar to Establishment. - :param establishment_slug: str Establishment slug + Return QuerySet with objects that similar to Restaurant. + :param restaurant_slug: str Establishment slug """ - establishment_qs = self.filter(slug=establishment_slug, - public_mark__isnull=False) - if establishment_qs.exists(): - establishment = establishment_qs.first() + restaurant_qs = self.filter(slug=restaurant_slug, + public_mark__isnull=False) + if restaurant_qs.exists(): + establishment = restaurant_qs.first() subquery_filter_by_distance = Subquery( - self.exclude(slug=establishment_slug) - .filter(image_url__isnull=False, public_mark__gte=10) - .has_published_reviews() - .annotate_distance(point=establishment.location) + self.similar_base(establishment) + .filter(public_mark__gte=10, + establishment_gallery__is_main=True) .order_by('distance')[:settings.LIMITING_QUERY_OBJECTS] .values('id') ) @@ -234,8 +245,38 @@ class EstablishmentQuerySet(models.QuerySet): .annotate_mark_similarity(mark=establishment.public_mark) \ .order_by('mark_similarity') \ .distinct('mark_similarity', 'id') + + def by_wine_region(self, wine_region): + """ + Return filtered QuerySet by wine region in wine origin. + :param wine_region: wine region. + """ + return self.filter(wine_origin__wine_region=wine_region).distinct() + + def by_wine_sub_region(self, wine_sub_region): + """ + Return filtered QuerySet by wine region in wine origin. + :param wine_sub_region: wine sub region. + """ + return self.filter(wine_origin__wine_sub_region=wine_sub_region).distinct() + + def similar_wineries(self, winery_slug: str): + """ + Return QuerySet with objects that similar to Winery. + :param establishment_slug: str Establishment slug + """ + winery_qs = self.filter(slug=winery_slug) + if winery_qs.exists(): + winery = winery_qs.first() + return self.similar_base(winery) \ + .order_by(F('wine_origins__wine_region').asc(), + F('wine_origins__wine_sub_region').asc()) \ + .annotate_distance(point=winery.location) \ + .order_by('distance') \ + .distinct('distance', 'wine_origins__wine_region', + 'wine_origins__wine_sub_region', 'id') else: - return self.none() + self.none() def last_reviewed(self, point: Point): """ diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index faa34bd9..5821a4c6 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -9,7 +9,6 @@ urlpatterns = [ path('', views.EstablishmentListView.as_view(), name='list'), path('recent-reviews/', views.EstablishmentRecentReviewListView.as_view(), name='recent-reviews'), - path('slug//similar/', views.EstablishmentSimilarListView.as_view(), name='similar'), path('slug//comments/', views.EstablishmentCommentListView.as_view(), name='list-comments'), path('slug//comments/create/', views.EstablishmentCommentCreateView.as_view(), name='create-comment'), @@ -17,4 +16,11 @@ urlpatterns = [ name='rud-comment'), path('slug//favorites/', views.EstablishmentFavoritesCreateDestroyView.as_view(), name='create-destroy-favorites'), + + # similar establishments + path('slug//similar/restaurants/', views.RestaurantSimilarListView.as_view(), + name='similar-restaurants'), + path('slug//similar/wineries/', views.WinerySimilarListView.as_view(), + name='similar-restaurants'), + ] diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index ba5cb23b..a7b90184 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -77,16 +77,28 @@ class EstablishmentRecentReviewListView(EstablishmentListView): return qs.last_reviewed(point=point) -class EstablishmentSimilarListView(EstablishmentListView): - """Resource for getting a list of establishments.""" - +class EstablishmentSimilarList(EstablishmentListView): + """Resource for getting a list of similar establishments.""" serializer_class = serializers.EstablishmentSimilarSerializer pagination_class = EstablishmentPortionPagination + +class RestaurantSimilarListView(EstablishmentSimilarList): + """Resource for getting a list of similar restaurants.""" + def get_queryset(self): """Override get_queryset method""" qs = super().get_queryset() - return qs.similar(establishment_slug=self.kwargs.get('slug')) + return qs.similar_restaurants(restaurant_slug=self.kwargs.get('slug')) + + +class WinerySimilarListView(EstablishmentSimilarList): + """Resource for getting a list of similar wineries.""" + + def get_queryset(self): + """Override get_queryset method""" + qs = super().get_queryset() + return qs.similar_wineries(winery_slug=self.kwargs.get('slug')) class EstablishmentTypeListView(generics.ListAPIView): diff --git a/project/settings/local.py b/project/settings/local.py index c56f9042..d9c7cab8 100644 --- a/project/settings/local.py +++ b/project/settings/local.py @@ -42,7 +42,7 @@ DATABASES = { 'HOST': os.environ.get('DB_HOSTNAME'), 'PORT': os.environ.get('DB_PORT'), 'OPTIONS': { - 'options': '-c search_path=gm' + 'options': '-c search_path=gm,public' }, }, 'legacy': {