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)
|
---|