Ticket #7934: f

File f, 2.9 KB (added by lkcl, 11 years ago)
Line 
1Index: 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)
Back to Top