diff --git a/apps/establishment/models.py b/apps/establishment/models.py index efe665ef..a0c9c44c 100644 --- a/apps/establishment/models.py +++ b/apps/establishment/models.py @@ -102,6 +102,20 @@ class EstablishmentQuerySet(models.QuerySet): default=False, output_field=models.BooleanField(default=False))) + def by_distance_from_point(self, center, radius, unit='m'): + """ + Returns nearest establishments + + :param center: point from which to find nearby establishments + :param radius: the maximum distance within the radius of which to look for establishments + :return: all establishments within the specified radius of specified point + :param unit: length unit e.g. m, km. Default is 'm'. + """ + + from django.contrib.gis.measure import Distance + kwargs = {unit: radius} + return self.filter(address__coordinates__distance_lte=(center, Distance(**kwargs))) + class Establishment(ProjectBaseMixin, ImageMixin, TranslatedFieldsMixin): """Establishment model.""" diff --git a/apps/establishment/views.py b/apps/establishment/views.py index 528d2377..7745af2d 100644 --- a/apps/establishment/views.py +++ b/apps/establishment/views.py @@ -111,9 +111,28 @@ class EstablishmentFavoritesCreateDestroyView(generics.CreateAPIView, generics.D obj = get_object_or_404( self.request.user.favorites.by_user(user=self.request.user) - .by_content_type(app_label='establishment', - model='establishment') - .by_object_id(object_id=self.kwargs['pk'])) + .by_content_type(app_label='establishment', + model='establishment') + .by_object_id(object_id=self.kwargs['pk'])) # May raise a permission denied self.check_object_permissions(self.request, obj) return obj + + +class EstablishmentNearestRetrieveView(EstablishmentMixin, JWTGenericViewMixin, generics.ListAPIView): + """Resource for getting list of nearest establishments.""" + serializer_class = serializers.EstablishmentListSerializer + filter_class = filters.EstablishmentFilter + + def get_queryset(self): + """Overrided method 'get_queryset'.""" + from django.contrib.gis.geos import Point + + center = Point(float(self.request.query_params["lat"]), float(self.request.query_params["lon"])) + radius = float(self.request.query_params["radius"]) + unit = self.request.query_params.get("unit", None) + by_distance_from_point_kwargs = {"center": center, "radius": radius, "unit": unit} + return super(EstablishmentNearestRetrieveView, self).get_queryset() \ + .by_distance_from_point(**{k: v for k, v in by_distance_from_point_kwargs.items() if v is not None}) \ + .by_country_code(code=self.request.country_code) \ + .annotate_in_favorites(user=self.request.user)