gault-millau/apps/establishment/views/web.py
2020-02-05 18:24:54 +03:00

270 lines
9.8 KiB
Python

"""Establishment app views."""
from django.conf import settings
from django.contrib.gis.geos import Point
from django.shortcuts import get_object_or_404
from rest_framework import generics, permissions
from comment import models as comment_models
from establishment import filters, models, serializers
from main import methods
from utils.pagination import PortionPagination
from utils.views import FavoritesCreateDestroyMixinView, CarouselCreateDestroyMixinView
class EstablishmentMixinView:
"""Establishment mixin."""
permission_classes = (permissions.AllowAny,)
def get_queryset(self):
"""Overridden method 'get_queryset'."""
qs = models.Establishment.objects.published() \
.with_base_related() \
.annotate_in_favorites(self.request.user)
if self.request.country_code:
qs = qs.by_country_code(self.request.country_code)
return qs
class EstablishmentListView(EstablishmentMixinView, generics.ListAPIView):
"""Resource for getting a list of establishments."""
filter_class = filters.EstablishmentFilter
serializer_class = serializers.EstablishmentListRetrieveSerializer
def get_queryset(self):
return super().get_queryset().with_schedule().with_reviews() \
.with_extended_address_related().with_currency_related() \
.with_certain_tag_category_related('category', 'restaurant_category') \
.with_certain_tag_category_related('cuisine', 'restaurant_cuisine') \
.with_certain_tag_category_related('shop_category', 'artisan_category') \
.with_certain_tag_category_related('distillery_type', 'distillery_type') \
.with_certain_tag_category_related('food_producer', 'producer_type')
class EstablishmentSimilarView(EstablishmentListView):
"""Resource for getting a list of similar establishments."""
serializer_class = serializers.EstablishmentSimilarSerializer
pagination_class = None
def get_base_object(self):
"""
Return base establishment instance for a getting list of similar establishments.
"""
establishment = get_object_or_404(models.Establishment.objects.all(),
slug=self.kwargs.get('slug'))
return establishment
def get_queryset(self):
"""Overridden get_queryset method."""
return EstablishmentMixinView.get_queryset(self) \
.has_location()
class EstablishmentRetrieveView(EstablishmentMixinView, generics.RetrieveAPIView):
"""Resource for getting a establishment."""
lookup_field = 'slug'
serializer_class = serializers.EstablishmentDetailSerializer
def get_queryset(self):
return super().get_queryset().with_extended_related() \
.with_certain_tag_category_related('distillery_type', 'distillery_type')
class EstablishmentMobileRetrieveView(EstablishmentRetrieveView):
serializer_class = serializers.MobileEstablishmentDetailSerializer
def get_queryset(self):
return super().get_queryset().prefetch_comments()
class EstablishmentRecentReviewListView(EstablishmentListView):
"""List view for last reviewed establishments."""
pagination_class = PortionPagination
def get_queryset(self):
"""Overridden method 'get_queryset'."""
qs = super().get_queryset()
query_params = self.request.query_params
if 'longitude' in query_params and 'latitude' in query_params:
longitude, latitude = query_params.get('longitude'), query_params.get('latitude')
else:
longitude, latitude = methods.determine_coordinates(self.request)
if not longitude or not latitude:
return qs.none()
point = Point(x=float(longitude), y=float(latitude), srid=settings.GEO_DEFAULT_SRID)
return qs.last_reviewed(point=point)
class RestaurantSimilarListView(EstablishmentSimilarView):
"""Resource for getting a list of similar restaurants."""
def get_queryset(self):
"""Overridden get_queryset method"""
qs = super(RestaurantSimilarListView, self).get_queryset()
base_establishment = self.get_base_object()
if base_establishment:
return qs.similar_restaurants(base_establishment)[:settings.QUERY_OUTPUT_OBJECTS]
else:
return EstablishmentMixinView.get_queryset(self) \
.none()
class WinerySimilarListView(EstablishmentSimilarView):
"""Resource for getting a list of similar wineries."""
def get_queryset(self):
"""Overridden get_queryset method"""
qs = EstablishmentSimilarView.get_queryset(self)
base_establishment = self.get_base_object()
if base_establishment:
return qs.similar_wineries(base_establishment)[:settings.QUERY_OUTPUT_OBJECTS]
else:
return qs.none()
class ArtisanProducerSimilarListView(EstablishmentSimilarView):
"""Resource for getting a list of similar artisan/producer(s)."""
def get_queryset(self):
"""Overridden get_queryset method"""
qs = super(ArtisanProducerSimilarListView, self).get_queryset()
base_establishment = self.get_base_object()
if base_establishment:
return qs.similar_artisans_producers(base_establishment)[:settings.QUERY_OUTPUT_OBJECTS]
else:
return qs.none()
class DistillerySimilarListView(EstablishmentSimilarView):
"""Resource for getting a list of similar distillery(s)."""
def get_queryset(self):
"""Overridden get_queryset method"""
qs = super(DistillerySimilarListView, self).get_queryset()
base_establishment = self.get_base_object()
if base_establishment:
return qs.similar_distilleries(base_establishment)[:settings.QUERY_OUTPUT_OBJECTS]
else:
return qs.none()
class FoodProducerSimilarListView(EstablishmentSimilarView):
"""Resource for getting a list of similar food producers(s)."""
def get_queryset(self):
"""Overridden get_queryset method"""
qs = super(FoodProducerSimilarListView, self).get_queryset()
base_establishment = self.get_base_object()
if base_establishment:
return qs.similar_food_producers(base_establishment)[:settings.QUERY_OUTPUT_OBJECTS]
else:
return qs.none()
class EstablishmentTypeListView(generics.ListAPIView):
"""Resource for getting a list of establishment types."""
permission_classes = (permissions.AllowAny, )
serializer_class = serializers.EstablishmentTypeBaseSerializer
queryset = models.EstablishmentType.objects.all()
class EstablishmentCommentCreateView(generics.CreateAPIView):
"""View for create new comment."""
lookup_field = 'slug'
serializer_class = serializers.EstablishmentCommentCreateSerializer
queryset = comment_models.Comment.objects.all()
class EstablishmentCommentListView(generics.ListAPIView):
"""View for return list of establishment comments."""
permission_classes = (permissions.AllowAny,)
serializer_class = serializers.EstablishmentCommentBaseSerializer
def get_queryset(self):
"""Override get_queryset method"""
establishment = get_object_or_404(models.Establishment, slug=self.kwargs['slug'])
return establishment.comments.public(self.request.user).order_by('-created')
class EstablishmentCommentRUDView(generics.RetrieveUpdateDestroyAPIView):
"""View for retrieve/update/destroy establishment comment."""
serializer_class = serializers.EstablishmentCommentBaseSerializer
queryset = models.Establishment.objects.all()
def get_object(self):
"""
Returns the object the view is displaying.
"""
queryset = self.filter_queryset(self.get_queryset())
establishment_obj = get_object_or_404(queryset,
slug=self.kwargs['slug'])
comment_obj = get_object_or_404(establishment_obj.comments.by_user(self.request.user),
pk=self.kwargs['comment_id'])
# May raise a permission denied
self.check_object_permissions(self.request, comment_obj)
return comment_obj
class EstablishmentFavoritesCreateDestroyView(FavoritesCreateDestroyMixinView):
"""View for create/destroy establishment from favorites."""
_model = models.Establishment
serializer_class = serializers.EstablishmentFavoritesCreateSerializer
class EstablishmentCarouselCreateDestroyView(CarouselCreateDestroyMixinView):
"""
EstablishmentCarousel by slug create/destroy establishment from carousel.
**POST**
```
Implement create EstablishmentCarousel method
```
**DELETE**
```
Implement delete EstablishmentCarousel method
```
"""
lookup_field = 'slug'
_model = models.Establishment
serializer_class = serializers.EstablishmentCarouselCreateSerializer
class EstablishmentNearestRetrieveView(EstablishmentListView, generics.ListAPIView):
"""Resource for getting list of nearest establishments."""
serializer_class = serializers.EstablishmentGeoSerializer
filter_class = filters.EstablishmentFilter
def get_queryset(self):
"""Overridden method 'get_queryset'."""
# todo: latitude and longitude
lat = self.request.query_params.get('lat')
lon = self.request.query_params.get('lon')
radius = self.request.query_params.get('radius')
unit = self.request.query_params.get('unit')
qs = super(EstablishmentNearestRetrieveView, self).get_queryset()
if lat and lon and radius and unit:
center = Point(float(lon), float(lat))
filter_kwargs = {'center': center, 'radius': float(radius), 'unit': unit}
return qs.by_distance_from_point(**{k: v for k, v in filter_kwargs.items()
if v is not None})
return qs