Reputation: 21
For my application, I need to find a point in my database that is the nearest to the point specified by user. This is my model:
class WaysVerticesPgr(models.Model):
id = models.BigIntegerField(primary_key=True)
osm_id = models.BigIntegerField(unique=True, blank=True, null=True)
cnt = models.IntegerField(blank=True, null=True)
chk = models.IntegerField(blank=True, null=True)
ein = models.IntegerField(blank=True, null=True)
eout = models.IntegerField(blank=True, null=True)
lon = models.DecimalField(max_digits=11, decimal_places=8, blank=True, null=True)
lat = models.DecimalField(max_digits=11, decimal_places=8, blank=True, null=True)
the_geom = models.PointField(blank=True, null=True)
And I am trying this code to find all points within a small radius (in this case o.oo5 degrees), annotate the distance between each of them and an input point, sort them by distance and return the first in the array:
from django.contrib.gis.db.models.functions import *
from .models import *
from django.contrib.gis.geos import *
from django.contrib.gis.measure import *
def get_closest_point(input):
input_point_geometry=GEOSGeometry('POINT('+input+')')
closest = WaysVerticesPgr.objects.filter(the_geom__dwithin=(input_point_geometry,0.005)).annotate(distance_between=input_point_geometry.distance('the_geom')).order_by(distance_between)[:1]
return closest
But I get an error 'distance() works only on other GEOS Geometries'. When I try converting the_geom to GEOSGeometry format:
closest = WaysVerticesPgr.objects.filter(the_geom__dwithin=(input_point_geometry,0.005)).annotate(distance_between=input_point_geometry.distance(GEOSGeometry('the_geom'))).order_by(distance_between)[:1]
I get an error:
'String or unicode input unrecognized as WKT EWKT, and HEXEWKB'. Which is kind of strange because the_geom field has the format 0101000020E6100000E7525C55F65DA1BF8FF5793139C34940 that seems to be HEX.
I managed to do it in a long way with a loop but this does not look nice and the performance is not good. But interestingly, conversion to GEOSGeometry works in this case:
def get_closest_point(input):
input_point_geometry=GEOSGeometry('POINT('+input+')')
closest = WaysVerticesPgr.objects.filter(the_geom__dwithin=(input_point_geometry,0.005))
dict_closest = {}
list_closest = []
for i in closest:
i = GEOSGeometry(i.the_geom)
distance_between=input_point_geometry.distance(i)
i = str(i.wkt)
dict_closest = {'Point':i,'Distance':distance_between}
list_closest.append(dict_closest)
sortlist=sorted(list_closest, key=itemgetter('Distance'), reverse=False)
return sortlist[0]
Does anybody have an idea how to make it work in a short way? I work with Django 1.9
, Python 3.5 and Postgres 9.5
with PostGIS
. I saw people in other threads suggested using another distance function that looks like distance = Distance(point1,point2), but it gives me an error that 3 arguments are given while only 1 or 2 are accepted (an input was two points of GEOSGeometry format).
Your help will be highly appreciated!
Upvotes: 0
Views: 1070
Reputation: 21
@ e4c5 Yes, I checked it. Turns out that GeoQuerySet.distance function has been deprecated since Django 1.9. Instead, this worked for me:
def get_closest_point(input):
input_point=GEOSGeometry('POINT('+input+')')
closest = WaysVerticesPgr.objects.filter(the_geom__dwithin=(input_point_geometry,0.005)).annotate(distance=Distance('the_geom', input_point)).order_by('distance').values('lon','lat')[0]
Thank you anyway (voted for your answer but it does not display because of my low reputation).
Upvotes: 2