我有这个模特
class Company(models.Model):
name = models.CharField(max_length = 50)
description = models.TextField()
latitude = models.FloatField()
longitude = models.FloatField()
owner = models.ForeignKey(User, on_delete = models.CASCADE, related_name = "company_owner")
category = models.ForeignKey(Category, on_delete = models.CASCADE)
def __str__(self):
return self.name
class Meta:
verbose_name_plural = "Companies"
def get_absolute_url(self):
return reverse('category_list')
#if want to redirect to its detail page then
# return reverse('company_detail' ,kwargs = {'pk' : self.pk})
def get_distance(self):
ip = get('https://api.ipify.org').text
reader = geoip2.database.Reader('categories/GeoLite2-City.mmdb')
response = reader.city(ip)
current_lat = response.location.latitude
current_lon = response.location.longitude
comp_lat = self.latitude
comp_lon = self.longitude
R = 6373.0
lat1 = radians(current_lat)
lon1 = radians(current_lon)
lat2 = radians(comp_lat)
lon2 = radians(comp_lon)
dlon = lon2 - lon1
dlat = lat2 - lat1
a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2
c = 2 * atan2(sqrt(a), sqrt(1 - a))
distance = R * c
return(distance)
我从get_distance()函数获得了用户位置和公司位置之间的距离。但是,如何将距离按升序排序? 由于距离与用户的不同位置不同,因此无法将距离存储在数据库中。 我想打印按距离升序排列的对象
答案 0 :(得分:0)
最好的解决方案是研究使用GeoDjango,它使您能够spatial queries。
除了可以做的其他事情distance lookups,这主要是您正在寻找的东西。然后,所有查询功能都使用适当的数据库扩展名(例如PostGIS用于postgres)驻留在数据库内部。如果您不能使用GeoDjango,请尝试执行原始SQL查询,例如,参见this question。
答案 1 :(得分:0)
由于这个问题仍然没有被接受的答案,并且有数十位研究员看到了它,所以我决定稍作讨论。
首先,我认为BernhardVallant和mrfackowiak已经指出了正确的解决方案。我将说明它的代码是什么样的。
将Geodjango添加到您的项目
来自官方文档“ GeoDjango打算成为世界级的地理Web框架”。基本上,它使您能够以各种方式(计算距离,基于地理形状过滤对象等)来操纵地理数据(坐标,栅格,项目)。
设置它需要一些步骤,许多人已经对此进行了详尽的解释。您可以从official documentation's tutorial开始。
更新您的模型
首先,导入GeoDjango的模型和特殊对象以获取地理数据。然后,使用以下更改更新模型。
# models.py
from django.contrib.gis.db import models
from django.contrib.gis.geos import GEOSGeometry, fromstr
# Company model inherits from GeoDjango's model
class Company(models.Model):
... # your other fields go here
latitude = models.FloatField()
longitude = models.FloatField()
geo_location = models.PointField(null=True) # New field
# New method to generate geo_location from lat, lng
def create_geo_location(self):
self.geo_location = fromstr(f'POINT({self.lng} {self.lat})', srid=4326)
# Overwrite save() to use create_geo_location()
def save(self, **kwargs):
""" Creates a geo_location value (Point), if no prior-value exist"""
if not self.geo_location:
self.create_geo_location()
您将不在这里使用get_distance()方法,而是将逻辑移至视图。
更新您的视图。py
这是您的视图的外观:
# views.py
from <your-app>.models import Company
from decimal import Decimal
from django.contrib.gis.geos import fromstr
from django.contrib.gis.db.models.functions import Distance
from django.contrib.gis.measure import D
class CompanyListView(ListView):
context_object_name = 'companies'
# Get user lat and lng using the logic in your get_distance() method and
# .. transom the values to Decimal
# ex. user_lat, user_lng = Decimal(45.5260525), Decimal(-73.5596788)
# user location is a geographic point value with a specific projection (srid)
user_location = fromstr(f'POINT({user_lng} {user_lat})', srid=4326)
queryset = Company.objects.filter(geo_location__dwithin=(user_location, D(m=2000)))
.annotate(distance_to_user = Distance("geo_location", user_location))
.order_by("distance_to_user")
该查询将获取距离用户2公里之内的所有Company实例。它还将创建一个带注释的新变量,称为distance_to_user,它将存储距离(以米为单位)。最后,它将对结果进行排序。
有一些我没有解释的有关地理数据和查询的细节,但是如果您要使用GeoDjango,最好对它们有所了解。我希望这会有所帮助。