Ticket #10159: geowherenode_expressions_fix_v2.diff
File geowherenode_expressions_fix_v2.diff, 8.1 KB (added by , 16 years ago) |
---|
-
django/contrib/gis/db/models/sql/where.py
1 1 import datetime 2 from django.db import connection 2 3 from django.db.models.fields import Field 4 from django.db.models.sql.expressions import SQLEvaluator 3 5 from django.db.models.sql.where import WhereNode 4 6 from django.contrib.gis.db.backend import get_geo_where_clause, SpatialBackend 7 qn = connection.ops.quote_name 5 8 6 9 class GeoAnnotation(object): 7 10 """ … … 37 40 # Not a geographic field, so call `WhereNode.add`. 38 41 return super(GeoWhereNode, self).add(data, connector) 39 42 else: 40 # `GeometryField.get_db_prep_lookup` returns a where clause41 # substitution array in addition to the parameters.42 where, params = field.get_db_prep_lookup(lookup_type, value)43 43 44 if isinstance(value, SQLEvaluator): 45 # If an expression is used, we are getting a database column so 46 # we we don't send to get_db_prep_lookup. 47 where = ['%s.%s' % tuple(map(qn, value.cols[value.expression]))] 48 params = () 49 else: 50 # `GeometryField.get_db_prep_lookup` returns a where clause 51 # substitution array in addition to the parameters. 52 where, params = field.get_db_prep_lookup(lookup_type, value) 53 44 54 # The annotation will be a `GeoAnnotation` object that 45 55 # will contain the necessary geometry field metadata for 46 56 # the `get_geo_where_clause` to construct the appropriate -
django/contrib/gis/tests/relatedapp/tests.py
1 1 import os, unittest 2 from django.contrib.gis.geos import * 2 from django.contrib.gis.db.models import F, Extent, Union 3 from django.contrib.gis.geos import GEOSGeometry, Point 3 4 from django.contrib.gis.tests.utils import no_mysql, postgis 4 5 from django.conf import settings 5 from models import City, Location, DirectoryEntry 6 from models import City, Location, DirectoryEntry, Parcel 6 7 7 8 cities = (('Aurora', 'TX', -97.516111, 33.058333), 8 9 ('Roswell', 'NM', -104.528056, 33.387222), … … 39 40 # US Survey Feet (thus a tolerance of 0 implies error w/in 1 survey foot). 40 41 if postgis: 41 42 tol = 3 42 nqueries = 4 # +1 for `postgis_lib_version`43 43 else: 44 44 tol = 0 45 nqueries = 346 45 47 46 def check_pnt(ref, pnt): 48 47 self.assertAlmostEqual(ref.x, pnt.x, tol) 49 48 self.assertAlmostEqual(ref.y, pnt.y, tol) 50 49 self.assertEqual(ref.srid, pnt.srid) 51 50 52 # Turning on debug so we can manually verify the number of SQL queries issued.53 # DISABLED: the number of queries count testing mechanism is way too brittle.54 #dbg = settings.DEBUG55 #settings.DEBUG = True56 from django.db import connection57 58 51 # Each city transformed to the SRID of their state plane coordinate system. 59 52 transformed = (('Kecksburg', 2272, 'POINT(1490553.98959621 314792.131023984)'), 60 53 ('Roswell', 2257, 'POINT(481902.189077221 868477.766629735)'), … … 65 58 # Doing this implicitly sets `select_related` select the location. 66 59 qs = list(City.objects.filter(name=name).transform(srid, field_name='location__point')) 67 60 check_pnt(GEOSGeometry(wkt, srid), qs[0].location.point) 68 #settings.DEBUG= dbg69 61 70 # Verifying the number of issued SQL queries.71 #self.assertEqual(nqueries, len(connection.queries))72 73 62 @no_mysql 74 63 def test04_related_aggregate(self): 75 64 "Testing the `extent` and `unionagg` GeoQuerySet aggregates on related geographic models." 76 if postgis:77 # One for all locations, one that excludes Roswell.78 all_extent = (-104.528060913086, 33.0583305358887,-79.4607315063477, 40.1847610473633)79 txpa_extent = (-97.51611328125, 33.0583305358887,-79.4607315063477, 40.1847610473633)80 e1 = City.objects.extent(field_name='location__point')81 e2 = City.objects.exclude(name='Roswell').extent(field_name='location__point')82 for ref, e in [(all_extent, e1), (txpa_extent, e2)]:83 for ref_val, e_val in zip(ref, e): self.assertAlmostEqual(ref_val, e_val)84 65 66 # This combines the Extent and Union aggregates into one query 67 aggs = City.objects.aggregate(Extent('location__point'), Union('location__point')) 68 69 # One for all locations, one that excludes Roswell. 70 all_extent = (-104.528060913086, 33.0583305358887,-79.4607315063477, 40.1847610473633) 71 txpa_extent = (-97.51611328125, 33.0583305358887,-79.4607315063477, 40.1847610473633) 72 e1 = City.objects.extent(field_name='location__point') 73 e2 = City.objects.exclude(name='Roswell').extent(field_name='location__point') 74 e3 = aggs['location__point__extent'] 75 76 for ref, e in [(all_extent, e1), (txpa_extent, e2)]: 77 for ref_val, e_val in zip(ref, e): self.assertAlmostEqual(ref_val, e_val) 78 85 79 # The second union is for a query that has something in the WHERE clause. 86 80 ref_u1 = GEOSGeometry('MULTIPOINT(-104.528056 33.387222,-97.516111 33.058333,-79.460734 40.18476)', 4326) 87 81 ref_u2 = GEOSGeometry('MULTIPOINT(-97.516111 33.058333,-79.460734 40.18476)', 4326) 88 82 u1 = City.objects.unionagg(field_name='location__point') 89 83 u2 = City.objects.exclude(name='Roswell').unionagg(field_name='location__point') 84 u3 = aggs['location__point__union'] 85 90 86 self.assertEqual(ref_u1, u1) 91 87 self.assertEqual(ref_u2, u2) 88 self.assertEqual(ref_u1, u3) 92 89 93 90 def test05_select_related_fk_to_subclass(self): 94 91 "Testing that calling select_related on a query over a model with an FK to a model subclass works" 95 92 # Regression test for #9752. 96 93 l = list(DirectoryEntry.objects.all().select_related()) 97 94 95 def test6_f_expressions(self): 96 "Testing F() expressions on Geometry fields." 97 # Constructing a dummy parcel border and getting the City FK 98 p1_border = GEOSGeometry('POLYGON((-97.501205 33.052520,-97.501205 33.052576,-97.501150 33.052576,-97.501150 33.052520,-97.501205 33.052520))') 99 p1_city = City.objects.get(name='Aurora') 100 101 # First parcel has incorrect center point that is equal to the City point. 102 p1 = Parcel.objects.create(name='P1', city=p1_city, center=p1_city.location.point, border=p1_border) 103 p2 = Parcel.objects.create(name='P2', city=p1_city, center=p1_border.centroid, border=p1_border) 104 105 # Should return the second Parcel, which has the center within the 106 # border. 107 qs = Parcel.objects.filter(center__within=F('border')) 108 self.assertEqual(1, len(qs)) 109 self.assertEqual('P2', qs[0].name) 110 111 # Should return the first Parcel, which has the center point equal 112 # to the point in the City ForeignKey. 113 qs = Parcel.objects.filter(center=F('city__location__point')) 114 self.assertEqual(1, len(qs)) 115 self.assertEqual('P1', qs[0].name) 116 98 117 # TODO: Related tests for KML, GML, and distance lookups. 99 118 100 119 def suite(): -
django/contrib/gis/tests/relatedapp/models.py
20 20 listing_text = models.CharField(max_length=50) 21 21 location = models.ForeignKey(AugmentedLocation) 22 22 objects = models.GeoManager() 23 24 class Parcel(models.Model): 25 name = models.CharField(max_length=30) 26 city = models.ForeignKey(City) 27 center = models.PointField() 28 border = models.PolygonField() 29 objects = models.GeoManager() 30 def __unicode__(self): return self.name