附近的商店,不使用 Geo 包,Django Rest
Nearby stores ,without using Geo packages, Django Rest
我需要列出某个地址附近的商店
这是我的代码:
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
在我的 apiView 中使用 post 方法接收经纬度地址 我这样做了 :
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)
我不知道为什么,但我遇到了 return 这个错误:
QuerySet.annotate() 收到非表达式:4783.728105194982
最好在 table 中存储一个地理点,而不是分别存储经度和纬度。这将提高视图的性能并简化代码
您的商店、地址模型应该如下所示
class MyModel(models.Model:
geopoint = GeometryField(null=True, blank=True)
然后你可以在你的视图中使用这样的东西:
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))
如果您需要更多说明,请告诉我
首先,当您尝试制作地理定位应用程序时,您应该使用 postgresql
及其 postgis
扩展,并且 django 有一个名为 geodjango
的强大包,您不再需要使用两个不同的字段名称 long
、lat
from django.contrib.gis.db import models
class Shop(models.Model):
city= models.CharField(max_length=100)
long_lat = models.PointField()
然后在你的 views.py
里面
from django.views import generic
from django.contrib.gis.geos import fromstr , Point
from django.contrib.gis.db.models.functions import Distance
from .models import Shop
Latitude = 31.2551 # for example , you can get long and lat from user using js
Longitude = 49.8824 #for example
user_location = Point(Latitude , Longitude , srid=4326)
class NearestShop(generic.ListView):
model = Shop
context_object_name = 'shops'
queryset = Shop.objects.annotate(distance=Distance('long_lat ',user_location)).order_by('distance').distinct('distance')
如果您使用 windows 并且无法配置 postgis
我有勇气在 windows
上使用 ubuntu 命令行
我最终这样做而不是使用注释(距离)。
不使用 Postgis 扩展。
#### see code in Question
list = {}
location = (address.lat, address.long)
for shop in shops:
dis = shop.distance_shop(location)
if dis <= 10.0:
list['name'] = shop.name
list['long'] = shop.long
list['lat'] = shop.lat
return Response({'message': 'no close shops to your address'}, status=status.HTTP_303_SEE_OTHER)
return Response({'shops in district': list}, status=status.HTTP_200_OK)
我需要列出某个地址附近的商店 这是我的代码:
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
在我的 apiView 中使用 post 方法接收经纬度地址 我这样做了 :
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)
我不知道为什么,但我遇到了 return 这个错误:
QuerySet.annotate() 收到非表达式:4783.728105194982
最好在 table 中存储一个地理点,而不是分别存储经度和纬度。这将提高视图的性能并简化代码
您的商店、地址模型应该如下所示
class MyModel(models.Model:
geopoint = GeometryField(null=True, blank=True)
然后你可以在你的视图中使用这样的东西:
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))
如果您需要更多说明,请告诉我
首先,当您尝试制作地理定位应用程序时,您应该使用 postgresql
及其 postgis
扩展,并且 django 有一个名为 geodjango
的强大包,您不再需要使用两个不同的字段名称 long
、lat
from django.contrib.gis.db import models
class Shop(models.Model):
city= models.CharField(max_length=100)
long_lat = models.PointField()
然后在你的 views.py
里面from django.views import generic
from django.contrib.gis.geos import fromstr , Point
from django.contrib.gis.db.models.functions import Distance
from .models import Shop
Latitude = 31.2551 # for example , you can get long and lat from user using js
Longitude = 49.8824 #for example
user_location = Point(Latitude , Longitude , srid=4326)
class NearestShop(generic.ListView):
model = Shop
context_object_name = 'shops'
queryset = Shop.objects.annotate(distance=Distance('long_lat ',user_location)).order_by('distance').distinct('distance')
如果您使用 windows 并且无法配置 postgis
我有勇气在 windows
我最终这样做而不是使用注释(距离)。 不使用 Postgis 扩展。
#### see code in Question
list = {}
location = (address.lat, address.long)
for shop in shops:
dis = shop.distance_shop(location)
if dis <= 10.0:
list['name'] = shop.name
list['long'] = shop.long
list['lat'] = shop.lat
return Response({'message': 'no close shops to your address'}, status=status.HTTP_303_SEE_OTHER)
return Response({'shops in district': list}, status=status.HTTP_200_OK)