I am using GeoDjango with PostGIS. Then I am into trouble on how to get the nearest record from the given coordinates from my postgres db table.
-
Please do not put tags in the title. – ThiefMaster Oct 24 '11 at 11:01
-
1I think your question does not contain enough information, and it's a very special topic. Try to transform your problem into a similar problem where you may get more answers because the number of knowledgable people is higher. – hochl Oct 24 '11 at 11:37
-
Is it a problem related to something about measures (i.e., calculating distances between two coordinates?) I don't know about GeoDjango, but if you need some help in calculation, don't hesitate to ask for it :-) – Joël Oct 25 '11 at 07:48
-
I need to solve it by GeoDjango way. I will research more then will update this post. – eros Oct 26 '11 at 08:53
-
Just want to add that I need to do it by GeoDjango/PostgreSQL/PostGIS way. – eros Oct 27 '11 at 00:07
6 Answers
This this the answer using GeoDjango with PostGIS
Point coordinates must be a GEOSGeometry object. To make it use
from django.contrib.gis.geos import GEOSGeometry
point = GEOSGeometry('POINT(5 23)')
Then, let's imagine that you have a "Restaurant" model And coordinates of the point. So, for the closest restaurant just use:
Restaurants.objects.distance(point).order_by('distance')[0]

- 480
- 5
- 17

- 1,284
- 11
- 8
-
`[0]` means the first record because of ordered result? what is `-distance`? is it a fieldname of geometry type of the model? – eros Oct 28 '11 at 00:07
-
Yes, [0] -- the first record of ordered result. About `-distance`: This method takes a geometry as a parameter, and attaches a distance attribute to every model in the returned queryset that contains the distance (as a Distance object) to the given geometry. – Pavel Shvedov Oct 28 '11 at 08:40
-
3+1 for being the django answer. But '-distance' should be 'distance'. Now you are selecting the restaurant furthest away – RickyA Dec 07 '11 at 20:35
-
I tried this but I'm getting "DataError: Coordinate values are out of range [-180 -90, 180 90] for GEOGRAPHY type". – dannyroa Mar 07 '14 at 22:59
PostGIS 2.0 and later can use KNN nearest-neighbour searching to get the nearest centroids. For example:
SELECT ST_Distance(geom, 'SRID=26910;POINT(34.5 -23.2)'::geometry) AS d
FROM mypoints
ORDER BY geom <-> 'SRID=26910;POINT(34.5 -23.2)'::geometry
LIMIT 1;

- 41,085
- 18
- 152
- 203
I have to agree with delawen's answer but using st_distance on its own will be very slow. So to speed up things you will have to make use of GIST indexes (note most PostGIS function incl. st_distance DO NOT make use of indexes see: postgis indexing recommendation).
So you would first create a buffer around the point and then check its bounding box using "&&" (this makes use of built in GIST index - so it would perform much much better ) and then you would check distance by "st_distance".
For example to get nearest "restaurant" from a given cood location (e.g. X=1,Y=1) you would write:
select *,st_distance(the_geom_col,st_geomfromtext('POINT(1 1)',27700)) as distance
from restaurants where st_buffer(st_geomfromtext('POINT(1 1)',27700),100)
&& "the_geom_col"
This would be very fast compared to "st_distance" but results may contain restaurants that are more than 100 meters from the given location (esp. when geometries are kept in line or polygon formats).
To get more accurate results, restaurants that are exactly with in 100 meters range, you append following to the query given above:
and st_distance(the_geom_col,st_geomfromtext('POINTFROMTEXT(1 1)',27700)) <= 100
This will still be more efficient and faster than using st_distance on its own. Because database will only run st_distance against records that fulfil the first criteria.
So as a rule of thumb, whenever you have to perform expensive spatial lookups try to:
- Filter out as many false results as possible by making use of special operators (see special operations in official postgis docs.
- Then write actual spatial relationship checker function.
- Always have GIST index on your "geometry" column.
- Add bounding boxes to your "geometries" by using st_addbbox.
- Routinely reindex and vacuum/analyze your tables.
Note: Size of buffer or actual distance has to be in projection system you are using i.e. if you are using EPSG:4326 (Lat/Long) then you have give these distances in degrees. For example 1 meter in real world = 0.00000899 degrees .. and 100 meters = do the maths :)

- 39
- 2
PostgreSQL/PostGIS users should use "<->" operator in ORDER BY clause to get "K nearest neighbors" (KNN), as said Mike T in this answer.
To get benefit from KNN-GiST performance improvement in GeoDjango you may write as following:
from django.contrib.gis.db.models.functions import GeomValue
from django.contrib.gis.geos import Point
from django.db.models.expressions import CombinedExpression, F
knn = 10
longitude = -96.876369
latitude = 29.905320
pnt = Point(longitude, latitude, srid=4326)
order_by_expression = CombinedExpression(F('geom'), '<->', GeomValue(pnt))
nearest_neighbors = Neighbor.objects.order_by(order_by_expression)[:knn]
I have no experience with GeoDjango, but on PostgreSQL/PostGIS you have the st_distance(..) function. So, you can order your results by st_distance(geom_column, your_coordinates) asc
and see what are the nearest rows.
If you have plain coordinates (no postgis geometry), you can convert your coordinates to a point with the geometryFromText function.
Is that what you were looking for? If not, try to be more explicit.

- 305
- 4
- 21
-
You got the idea of what am looking for. I tried it with success but need to consider also the performance. If there is other way, please guide us. – eros Oct 27 '11 at 00:05
-
Did you try a spatial index on the geometry column? – María Arias de Reyna Domínguez Oct 14 '13 at 10:00
Using PostGIS and GeoDjango to find your nearest neighbour
Consider this the model:
from django.contrib.gis.geos import Point
from django.contrib.gis.db import models
class Store(models.Model):
name = models.CharField(max_length=100)
location = models.PointField(geography=True, srid=4326)
longitude = models.FloatField()
latitude = models.FloatField()
objects = models.GeoManager()
def save(self, **kwargs):
self.location = Point(self.longitude, self.latitude)
super(Store, self).save(**kwargs)
In a view get all the points of interest within a 100 mile radius of a specified longitude / latitude:
from django.contrib.gis.geos import Point
from django.contrib.gis.measure import D
point = Point(lng, lat)
points = Store.objects.filter(
location__distance_lte=(point, D(mi=100))
).distance(point).order_by('distance')
Show the results in a template:
<ul>
{% for point in points %}
<li>{{ point.name }} is {{ point.distance.mi|floatformat }} miles away</li>
{% endfor %}
</ul>

- 1,004
- 11
- 13