diff --git a/api_spot/api/serializers/locations.py b/api_spot/api/serializers/locations.py index 7910dd9d..d0ce29fd 100644 --- a/api_spot/api/serializers/locations.py +++ b/api_spot/api/serializers/locations.py @@ -19,7 +19,9 @@ class LocationGetSerializer(serializers.ModelSerializer): read_only=True, source='location_extra_photo' ) - is_favorited = serializers.SerializerMethodField() + low_price = serializers.DecimalField(max_digits=10, decimal_places=2) + rating = serializers.DecimalField(max_digits=3, decimal_places=2) + is_favorited = serializers.BooleanField(default=False) coordinates = serializers.SerializerMethodField() class Meta: @@ -35,7 +37,6 @@ class Meta: 'main_photo', 'extra_photo', 'rating', - 'low_price', 'short_annotation', 'description', 'is_favorited', @@ -45,15 +46,6 @@ class Meta: 'days_open' ) - def get_is_favorited(self, instance, *args, **kwargs) -> bool: - """ - Отображение наличия location в избранном при листинге location. - """ - user = self.context['request'].user - if not user.is_authenticated: - return False - return instance.favorites.filter(user_id=user.id).exists() - def get_coordinates(self, instance) -> list[Decimal]: """ Список координат diff --git a/api_spot/api/views/locations.py b/api_spot/api/views/locations.py index 3d52d2b7..183aa3c4 100644 --- a/api_spot/api/views/locations.py +++ b/api_spot/api/views/locations.py @@ -1,3 +1,4 @@ +from django.db.models import Avg, Count, Min, Prefetch from django_filters.rest_framework import DjangoFilterBackend from drf_spectacular.utils import extend_schema from rest_framework import filters @@ -18,7 +19,9 @@ class LocationViewSet(RetrieveListViewSet): Представление подробной информации о локациях с возможностью фильтрации по названию, категориям, метро и избранному. """ - queryset = Location.objects.all().prefetch_related('location_extra_photo') + queryset = Location.objects.all().prefetch_related( + Prefetch('location_extra_photo') + ) serializer_class = LocationGetSerializer permission_classes = (AllowAny,) pagination_class = LimitOffsetPagination @@ -26,6 +29,19 @@ class LocationViewSet(RetrieveListViewSet): filterset_class = LocationFilter search_fields = ('$name', ) + def get_queryset(self): + user = self.request.user + if user.is_authenticated: + return super().get_queryset().annotate( + is_favorited=Count('favorites', favorites__user=user), + low_price=Min('spots__price__total_price'), + rating=Avg('spots__orders__reviews__rating'), + ) + return super().get_queryset().annotate( + low_price=Min('spots__price__total_price'), + rating=Avg('spots__orders__reviews__rating'), + ) + @extend_schema( tags=('locations',) @@ -43,6 +59,19 @@ class LocationShortListAPIView(ListAPIView): filterset_class = LocationFilter search_fields = ('$name', ) + def get_queryset(self): + user = self.request.user + if user.is_authenticated: + return super().get_queryset().annotate( + is_favorited=Count('favorites', favorites__user=user), + low_price=Min('spots__price__total_price'), + rating=Avg('spots__orders__reviews__rating') + ) + return super().get_queryset().annotate( + low_price=Min('spots__price__total_price'), + rating=Avg('spots__orders__reviews__rating'), + ) + @extend_schema( tags=('locations',) @@ -51,9 +80,14 @@ class LocationMapListAPIView(ListAPIView): """ Представление краткой информации о локациях для отображения на карте. """ - queryset = Location.objects.all().prefetch_related('small_main_photo') + queryset = Location.objects.all().select_related('small_main_photo') serializer_class = LocationMapSerializer permission_classes = (AllowAny,) pagination_class = LimitOffsetPagination filter_backends = (DjangoFilterBackend,) filterset_class = LocationFilter + + def get_queryset(self): + return super().get_queryset().annotate( + rating=Avg('spots__orders__reviews__rating') + ) diff --git a/api_spot/spots/models/location.py b/api_spot/spots/models/location.py index 36b14981..35e99879 100644 --- a/api_spot/spots/models/location.py +++ b/api_spot/spots/models/location.py @@ -5,9 +5,8 @@ DAYS_CHOICES, END_CHOICES, LAT_MAX, LAT_MIN, LAT_MSG_ERROR, LONG_MAX, LONG_MIN, LONG_MSG_ERROR, MEETING_ROOM, NAME_CACHE_MEETING_ROOM, NAME_CACHE_WORKSPACE, START_CHOICES, WORK_SPACE, - ) -from spots.services import count_spots, get_low_price, get_rating_location +from spots.services import count_spots class Location(models.Model): @@ -117,18 +116,6 @@ def count_meeting_room(self, *args, **kwargs) -> int: """ return count_spots(self, MEETING_ROOM, NAME_CACHE_MEETING_ROOM) - def rating(self, *args, **kwargs) -> float: - """ - Получение среднего рейтинга по отзывам. - """ - return get_rating_location(self) - - def low_price(self, *args, **kwargs) -> int: - """ - Минимальная цена. - """ - return get_low_price(self) - def get_full_address_str(self) -> str: """ Полный адрес.