Changeset 6441
- Timestamp:
- 09/30/07 12:44:13 (1 year ago)
- Files:
-
- django/branches/gis/django/contrib/gis/db/backend/__init__.py (modified) (1 diff)
- django/branches/gis/django/contrib/gis/db/models/manager.py (modified) (1 diff)
- django/branches/gis/django/contrib/gis/db/models/query.py (modified) (3 diffs)
- django/branches/gis/django/contrib/gis/tests/geoapp/tests.py (modified) (8 diffs)
- django/branches/gis/django/contrib/gis/tests/__init__.py (modified) (3 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/gis/django/contrib/gis/db/backend/__init__.py
r6439 r6441 17 17 FieldFound, LOOKUP_SEPARATOR, QUERY_TERMS 18 18 from django.utils.datastructures import SortedDict 19 20 # These routines default to False 21 ASGML, ASKML, UNION = (False, False, False) 19 22 20 23 if settings.DATABASE_ENGINE == 'postgresql_psycopg2': django/branches/gis/django/contrib/gis/db/models/manager.py
r5881 r6441 8 8 return GeoQuerySet(model=self.model) 9 9 10 def kml(self, field_name, **kwargs):11 return self.get_query_set(). kml(field_name, **kwargs)10 def gml(self, *args, **kwargs): 11 return self.get_query_set().gml(*args, **kwargs) 12 12 13 def transform(self, field_name, **kwargs): 14 return self.get_query_set().transform(field_name, **kwargs) 13 def kml(self, *args, **kwargs): 14 return self.get_query_set().kml(*args, **kwargs) 15 16 def transform(self, *args, **kwargs): 17 return self.get_query_set().transform(*args, **kwargs) 18 19 def union(self, *args, **kwargs): 20 return self.get_query_set().union(*args, **kwargs) django/branches/gis/django/contrib/gis/db/models/query.py
r6437 r6441 2 2 from django.core.exceptions import ImproperlyConfigured 3 3 from django.db import connection 4 from django.db.models.query import Q, QuerySet, handle_legacy_orderlist, quote_only_if_word, orderfield2column, fill_table_cache4 from django.db.models.query import EmptyResultSet, Q, QuerySet, handle_legacy_orderlist, quote_only_if_word, orderfield2column, fill_table_cache 5 5 from django.db.models.fields import FieldDoesNotExist 6 6 from django.utils.datastructures import SortedDict 7 7 from django.contrib.gis.db.models.fields import GeometryField 8 from django.contrib.gis.db.backend import parse_lookup # parse_lookup depends on the spatial database backend. 8 # parse_lookup depends on the spatial database backend. 9 from django.contrib.gis.db.backend import parse_lookup, ASGML, ASKML, UNION 10 from django.contrib.gis.geos import GEOSGeometry 9 11 10 12 class GeoQ(Q): … … 144 146 #### Methods specific to the GeoQuerySet #### 145 147 def _field_column(self, field): 148 "Helper function that returns the database column for the given field." 146 149 qn = connection.ops.quote_name 147 150 return "%s.%s" % (qn(self.model._meta.db_table), 148 151 qn(field.column)) 149 152 153 def _geo_column(self, field_name): 154 """ 155 Helper function that returns False when the given field name is not an 156 instance of a GeographicField, otherwise, the database column for the 157 geographic field is returned. 158 """ 159 field = self.model._meta.get_field(field_name) 160 if isinstance(field, GeometryField): 161 return self._field_column(field) 162 else: 163 return False 164 165 def gml(self, field_name, precision=8, version=2): 166 """ 167 Returns GML representation of the given field in a `gml` attribute 168 on each element of the GeoQuerySet. 169 """ 170 # Is GML output supported? 171 if not ASGML: 172 raise ImproperlyConfigured('AsGML() stored procedure not available.') 173 174 # Is the given field name a geographic field? 175 field_col = self._geo_column(field_name) 176 if not field_col: 177 raise TypeError('GML output only available on GeometryFields') 178 179 # Adding AsGML function call to SELECT part of the SQL. 180 return self.extra(select={'gml':'%s(%s,%s,%s)' % (ASGML, field_col, precision, version)}) 181 150 182 def kml(self, field_name, precision=8): 151 """Returns KML representation of the given field name in a `kml` 152 attribute on each element of the QuerySet.""" 183 """ 184 Returns KML representation of the given field name in a `kml` 185 attribute on each element of the GeoQuerySet. 186 """ 153 187 # Is KML output supported? 154 try: 155 from django.contrib.gis.db.backend.postgis import ASKML 156 except ImportError: 157 raise ImproperlyConfigured, 'AsKML() only available in PostGIS versions 1.2.1 and greater.' 158 188 if not ASKML: 189 raise ImproperlyConfigured('AsKML() stored procedure not available.') 190 191 # Is the given field name a geographic field? 192 field_col = self._geo_column(field_name) 193 if not field_col: 194 raise TypeError('KML output only available on GeometryFields.') 195 196 # Adding the AsKML function call to SELECT part of the SQL. 197 return self.extra(select={'kml':'%s(%s,%s)' % (ASKML, field_col, precision)}) 198 199 def transform(self, field_name, srid=4326): 200 """ 201 Transforms the given geometry field to the given SRID. If no SRID is 202 provided, the transformation will default to using 4326 (WGS84). 203 """ 159 204 # Is the given field name a geographic field? 160 205 field = self.model._meta.get_field(field_name) 161 206 if not isinstance(field, GeometryField): 162 raise TypeError, 'KML output only available on GeometryField fields.' 163 field_col = self._field_column(field) 164 165 # Adding the AsKML function call to the SELECT part of the SQL. 166 return self.extra(select={'kml':'%s(%s,%s)' % (ASKML, field_col, precision)}) 167 168 def transform(self, field_name, srid=4326): 169 """Transforms the given geometry field to the given SRID. If no SRID is 170 provided, the transformation will default to using 4326 (WGS84).""" 171 field = self.model._meta.get_field(field_name) 172 if not isinstance(field, GeometryField): 173 raise TypeError, 'ST_Transform() only available for GeometryField fields.' 207 raise TypeError('ST_Transform() only available for GeometryFields') 174 208 175 209 # Setting the key for the field's column with the custom SELECT SQL to … … 180 214 return self._clone() 181 215 182 216 def union(self, field_name): 217 """ 218 Performs an aggregate union on the given geometry field. Returns 219 None if the GeoQuerySet is empty. 220 """ 221 # Making sure backend supports the Union stored procedure 222 if not UNION: 223 raise ImproperlyConfigured('Union stored procedure not available.') 224 225 # Getting the geographic field column 226 field_col = self._geo_column(field_name) 227 if not field_col: 228 raise TypeError('Aggregate Union only available on GeometryFields.') 229 230 # Getting the SQL for the query. 231 try: 232 select, sql, params = self._get_sql_clause() 233 except EmptyResultSet: 234 return None 235 236 # Replacing the select with a call to the ST_Union stored procedure 237 # on the geographic field column. 238 union_sql = ('SELECT %s(%s)' % (UNION, field_col)) + sql 239 cursor = connection.cursor() 240 cursor.execute(union_sql, params) 241 242 # Pulling the HEXEWKB from the returned cursor. 243 hex = cursor.fetchone()[0] 244 if hex: return GEOSGeometry(hex) 245 else: return None django/branches/gis/django/contrib/gis/tests/geoapp/tests.py
r6243 r6441 7 7 def test01_initial_sql(self): 8 8 "Testing geographic initial SQL." 9 10 9 # Ensuring that data was loaded from initial SQL. 11 10 self.assertEqual(2, Country.objects.count()) … … 72 71 nullstate.delete() 73 72 74 def test03 _kml(self):73 def test03a_kml(self): 75 74 "Testing KML output from the database using GeoManager.kml()." 76 # Should throw an error trying to get KML from a non-geometry field. 77 try: 78 qs = City.objects.all().kml('name') 79 except TypeError: 80 pass 81 else: 82 self.fail('Expected a TypeError exception') 75 # Should throw a TypeError when trying to obtain KML from a 76 # non-geometry field. 77 qs = City.objects.all() 78 self.assertRaises(TypeError, qs.kml, 'name') 83 79 84 80 # Ensuring the KML is as expected. … … 86 82 self.assertEqual('<Point><coordinates>-104.609252,38.255001,0</coordinates></Point>', ptown.kml) 87 83 84 def test03b_gml(self): 85 "Testing GML output from the database using GeoManager.gml()." 86 # Should throw a TypeError when tyring to obtain GML from a 87 # non-geometry field. 88 qs = City.objects.all() 89 self.assertRaises(TypeError, qs.gml, 'name') 90 ptown = City.objects.gml('point', precision=9).get(name='Pueblo') 91 self.assertEqual('<gml:Point srsName="EPSG:4326"><gml:coordinates>-104.609252,38.255001</gml:coordinates></gml:Point>', ptown.gml) 92 88 93 def test04_transform(self): 89 "Testing the transform() queryset method." 90 94 "Testing the transform() GeoManager method." 91 95 # Pre-transformed points for Houston and Pueblo. 92 96 htown = fromstr('POINT(1947516.83115183 6322297.06040572)', srid=3084) … … 104 108 105 109 def test10_contains_contained(self): 106 "Testing the 'contained' and 'contains' lookup types." 107 110 "Testing the 'contained', 'contains', and 'bbcontains' lookup types." 108 111 # Getting Texas, yes we were a country -- once ;) 109 112 texas = Country.objects.get(name='Texas') … … 138 141 self.assertEqual(0, len(Country.objects.filter(mpoly__contains=okcity.point.wkt))) # Qeury w/WKT 139 142 143 # OK City is contained w/in bounding box of Texas. 144 qs = Country.objects.filter(mpoly__bbcontains=okcity.point) 145 self.assertEqual(1, len(qs)) 146 self.assertEqual('Texas', qs[0].name) 147 140 148 def test11_lookup_insert_transform(self): 141 149 "Testing automatic transform for lookups and inserts." 142 143 150 # San Antonio in 'WGS84' (SRID 4326) and 'NAD83(HARN) / Texas Centric Lambert Conformal' (SRID 3084) 144 151 sa_4326 = 'POINT (-98.493183 29.424170)' … … 162 169 def test12_null_geometries(self): 163 170 "Testing NULL geometry support." 164 165 171 # Querying for both NULL and Non-NULL values. 166 172 nullqs = State.objects.filter(poly__isnull=True) … … 183 189 def test13_left_right(self): 184 190 "Testing the 'left' and 'right' lookup types." 185 186 191 # Left: A << B => true if xmax(A) < xmin(B) 187 192 # Right: A >> B => true if xmin(A) > xmax(B) … … 262 267 self.assertEqual(c.point, None) 263 268 269 def test17_union(self): 270 "Testing the union() GeoManager method." 271 tx = Country.objects.get(name='Texas').mpoly 272 # Houston, Dallas, San Antonio 273 union = fromstr('MULTIPOINT(-98.493183 29.424170,-96.801611 32.782057,-95.363151 29.763374)') 274 qs = City.objects.filter(point__within=tx) 275 self.assertRaises(TypeError, qs.union, 'name') 276 u = qs.union('point') 277 self.assertEqual(True, union.equals_exact(u, 10)) # Going up to 10 digits of precision. 278 qs = City.objects.filter(name='NotACity') 279 self.assertEqual(None, qs.union('point')) 280 264 281 def suite(): 265 282 s = unittest.TestSuite() django/branches/gis/django/contrib/gis/tests/__init__.py
r6436 r6441 3 3 from unittest import TestSuite, TextTestRunner 4 4 from django.contrib.gis.gdal import HAS_GDAL 5 6 5 7 6 # Tests that do not require setting up and tearing down a spatial database. … … 38 37 def run_tests(module_list, verbosity=1, interactive=True): 39 38 """ 40 Run the tests that require creation of a spatial database. Does not 41 yet work on Windows platforms. 39 Run the tests that require creation of a spatial database. 42 40 43 41 In order to run geographic model tests the DATABASE_USER will require … … 50 48 (3) Start this database `pg_ctl -D /path/to/user/db start` 51 49 52 Make sure your settings.py matches the settings of the user database. For example, set the 53 same port number (`DATABASE_PORT=5433`). DATABASE_NAME or TEST_DATABSE_NAME must be set, 54 along with DATABASE_USER. 50 On Windows platforms simply use the pgAdmin III utility to add superuser 51 priviliges to your database user. 52 53 Make sure your settings.py matches the settings of the user database. 54 For example, set the same port number (`DATABASE_PORT=5433`). 55 DATABASE_NAME or TEST_DATABSE_NAME must be set, along with DATABASE_USER. 55 56 56 57 In settings.py set TEST_RUNNER='django.contrib.gis.tests.run_tests'. 57 58 58 Finally, this assumes that the PostGIS SQL files (lwpostgis.sql and spatial_ref_sys.sql) 59 are installed in /usr/local/share. If they are not, add `POSTGIS_SQL_PATH=/path/to/sql` 60 in your settings.py. 59 Finally, this assumes that the PostGIS SQL files (lwpostgis.sql and 60 spatial_ref_sys.sql) are installed in the directory specified by 61 `pg_config --sharedir` (and defaults to /usr/local/share if that fails). 62 This behavior is overridden if `POSTGIS_SQL_PATH` is in your settings. 63 64 Windows users should use the POSTGIS_SQL_PATH because the output 65 of `pg_config` uses paths like 'C:/PROGRA~1/POSTGR~1/..'. 61 66 62 The tests may be run by invoking `./manage.py test`.67 Finally, the tests may be run by invoking `./manage.py test`. 63 68 """ 64 69 from django.conf import settings
