diff --git a/apps/establishment/models.py b/apps/establishment/models.py index 9ecf38c2..ab7f14fa 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -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): """ diff --git a/apps/establishment/urls/common.py b/apps/establishment/urls/common.py index 68ba2b16..046667df 100644 --- a/apps/establishment/urls/common.py +++ b/apps/establishment/urls/common.py @@ -21,6 +21,8 @@ urlpatterns = [ path('slug//similar/', views.RestaurantSimilarListView.as_view(), name='similar-restaurants'), path('slug//similar/wineries/', views.WinerySimilarListView.as_view(), - name='similar-restaurants'), + name='similar-wineries'), + path('slug//similar/artisans/', views.ArtisanSimilarListView.as_view(), + name='similar-artisans'), ] diff --git a/apps/establishment/views/web.py b/apps/establishment/views/web.py index 9e6dc026..4253b6a6 100644 --- a/apps/establishment/views/web.py +++ b/apps/establishment/views/web.py @@ -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."""