I need to list stores nearby an address Here is my code :
class Shop(TimeStamp):
city = models.CharField(max_length=15, choices=CITIES, blank=True)
lat = models.DecimalField(decimal_places=6, max_digits=10, verbose_name='latitude', default=None)
long = models.DecimalField(decimal_places=6, max_digits=10, verbose_name='longitude', default=None)
def distance_shop(self, location):
return distance((self.lat, self.long), location)
#####################
#this is the function I used for calculating distance I used haversine distance(origin, destination)
def distance(origin, destination):
lat1, lon1 = origin
lat2, lon2 = destination
radius = 6371 # km
dlat = math.radians(lat2 - lat1)
dlon = math.radians(lon2 - lon1)
a = math.sin(dlat / 2) * math.sin(dlat / 2) + math.cos(math.radians(lat1))* math.cos(math.radians(lat2)) * math.sin(dlon/2)*math.sin(dlon / 2)
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
d = radius * c
return d
in my apiView using post method receiving an address lat and long I did this :
class NearbyShops(APIView):
permission_classes = [IsAuthenticated]
serializer_class = NearbyShopsSerializer
def post(self, request):
data = request.data
serializer = NearbyShopsSerializer(data=data)
if serializer.is_valid(raise_exception=True):
try:
address = DeliveryAddress.objects.get(client=request.user, lat=serializer.data.get('address_lat'),
long=serializer.data.get('address_long'))
except DeliveryAddress().DoesNotExist:
return Response({"error": "This address doesn't exist"}, status=status.HTTP_404_NOT_FOUND)
try:
shops = Shop.objects.filter(city=address.city)
except Shop().DoesNotExist:
return Response({"error": "No shops in this city address"},
status=status.HTTP_417_EXPECTATION_FAILED)
list = {}
for shop in shops:
location = (address.lat, address.long)
dis = shop.distance_shop(location)
shops = shops.annotate(distance=dis).order_by('distance')
closest = Shop.objects.filter(distance__lt=10.0)
for close in closest:
list['name'] = close.name
list['long'] = close.long
list['lat'] = close.lat
return Response({'shops': list}, status=status.HTTP_200_OK)
I don't know why , but I get in return this error :
QuerySet.annotate() received non-expression(s): 4783.728105194982
It's better to store a geopoint in your table rather than storing longitude and latitude separately. This will improve the performance of your view and simplify your code
your Shop, Address model should look like this
class MyModel(models.Model:
geopoint = GeometryField(null=True, blank=True)
Then you can use something like this in your view:
geopoint = Point(address_long, address_lat)
closest_shops = Shop.objects.filter(geopoint__distance_lte=(place.geometry, D(m=10.0)).annotate(distance=Distance('geometry', geopoint))
Please let me know if you need more clarification