def nearest_to(self, point, number=5, geom_column='latlon', from_srid=2163, to_srid=2163, within_range=None): """finds the model objects nearest to a given point `point` is a tuple of (x, y) in the spatial ref sys given by `from_srid` returns a list of tuples, sorted by increasing distance from the given `point`. each tuple being (model_object, dist), where distance is in the units of the spatial ref sys given by `to_srid`""" if not isinstance(point, tuple): raise TypeError from string import Template cursor = connection.cursor() x, y = point table = self.model._meta.db_table distance_clause = '' if within_range: distance_clause = "AND (Distance(GeomFromText('POINT($x $y)', $from_srid), $geom_column) <= %f)" % within_range sql = Template(""" SELECT id, Length(Transform(SetSRID(MakeLine($geom_column, GeomFromText('POINT(' || $x || ' ' || $y || ')', $from_srid)), $from_srid), $to_srid)) FROM $table WHERE $geom_column IS NOT NULL %s ORDER BY Distance(GeomFromText('POINT($x $y)', $from_srid), $geom_column) ASC LIMIT $number; """ % distance_clause) cursor.execute(sql.substitute(locals())) nearbys = cursor.fetchall() # get a list of primary keys of the nearby model objects ids = [p[0] for p in nearbys] # get a list of distances from the model objects dists = [p[1] for p in nearbys] places = self.filter(id__in=ids) # the QuerySet comes back in an undefined order; let's # order it by distance from the given point def order_by(objects, listing, name): """a convenience method that takes a list of objects, and orders them by comparing an attribute given by `name` to a sorted listing of values of the same length.""" sorted = [] for i in listing: for obj in objects: if getattr(obj, name) == i: sorted.append(obj) return sorted return zip(order_by(places, ids, 'id'), dists)