| 1 | Index: django/contrib/gis/db/models/manager.py
|
|---|
| 2 | ===================================================================
|
|---|
| 3 | --- django/contrib/gis/db/models/manager.py (revision 8066)
|
|---|
| 4 | +++ django/contrib/gis/db/models/manager.py (working copy)
|
|---|
| 5 | @@ -1,5 +1,6 @@
|
|---|
| 6 | from django.db.models.manager import Manager
|
|---|
| 7 | from django.contrib.gis.db.models.query import GeoQuerySet
|
|---|
| 8 | +from django.db import connection
|
|---|
| 9 |
|
|---|
| 10 | class GeoManager(Manager):
|
|---|
| 11 | "Overrides Manager to return Geographic QuerySets."
|
|---|
| 12 | @@ -75,3 +76,53 @@
|
|---|
| 13 |
|
|---|
| 14 | def unionagg(self, *args, **kwargs):
|
|---|
| 15 | return self.get_query_set().unionagg(*args, **kwargs)
|
|---|
| 16 | +
|
|---|
| 17 | + def nearest_to(self, point, number=5, geom_column='latlon',
|
|---|
| 18 | + from_srid=2163, to_srid=2163,
|
|---|
| 19 | + within_range=None):
|
|---|
| 20 | + """finds the model objects nearest to a given point
|
|---|
| 21 | +
|
|---|
| 22 | + `point` is a tuple of (x, y) in the spatial ref sys given by `from_srid`
|
|---|
| 23 | +
|
|---|
| 24 | + returns a list of tuples, sorted by increasing distance from the given `point`.
|
|---|
| 25 | + each tuple being (model_object, dist), where distance is in the units of the
|
|---|
| 26 | + spatial ref sys given by `to_srid`"""
|
|---|
| 27 | + if not isinstance(point, tuple):
|
|---|
| 28 | + raise TypeError
|
|---|
| 29 | + from string import Template
|
|---|
| 30 | + cursor = connection.cursor()
|
|---|
| 31 | + x, y = point
|
|---|
| 32 | + table = self.model._meta.db_table
|
|---|
| 33 | + distance_clause = ''
|
|---|
| 34 | + if within_range:
|
|---|
| 35 | + distance_clause = "AND (Distance(GeomFromText('POINT($x $y)', $from_srid), $geom_column) <= %f)" % within_range
|
|---|
| 36 | + sql = Template("""
|
|---|
| 37 | + SELECT id,
|
|---|
| 38 | + Length(Transform(SetSRID(MakeLine($geom_column, GeomFromText('POINT(' || $x || ' ' || $y || ')', $from_srid)), $from_srid), $to_srid))
|
|---|
| 39 | +
|
|---|
| 40 | +
|
|---|
| 41 | + FROM $table
|
|---|
| 42 | + WHERE $geom_column IS NOT NULL %s
|
|---|
| 43 | + ORDER BY Distance(GeomFromText('POINT($x $y)', $from_srid), $geom_column) ASC
|
|---|
| 44 | + LIMIT $number;
|
|---|
| 45 | + """ % distance_clause)
|
|---|
| 46 | + cursor.execute(sql.substitute(locals()))
|
|---|
| 47 | + nearbys = cursor.fetchall()
|
|---|
| 48 | + # get a list of primary keys of the nearby model objects
|
|---|
| 49 | + ids = [p[0] for p in nearbys]
|
|---|
| 50 | + # get a list of distances from the model objects
|
|---|
| 51 | + dists = [p[1] for p in nearbys]
|
|---|
| 52 | + places = self.filter(id__in=ids)
|
|---|
| 53 | + # the QuerySet comes back in an undefined order; let's
|
|---|
| 54 | + # order it by distance from the given point
|
|---|
| 55 | + def order_by(objects, listing, name):
|
|---|
| 56 | + """a convenience method that takes a list of objects,
|
|---|
| 57 | + and orders them by comparing an attribute given by `name`
|
|---|
| 58 | + to a sorted listing of values of the same length."""
|
|---|
| 59 | + sorted = []
|
|---|
| 60 | + for i in listing:
|
|---|
| 61 | + for obj in objects:
|
|---|
| 62 | + if getattr(obj, name) == i:
|
|---|
| 63 | + sorted.append(obj)
|
|---|
| 64 | + return sorted
|
|---|
| 65 | + return zip(order_by(places, ids, 'id'), dists)
|
|---|