Changeset 7028
- Timestamp:
- 01/21/08 19:22:27 (6 months ago)
- Files:
-
- django/branches/gis/django/contrib/gis/db/backend/__init__.py (modified) (4 diffs)
- django/branches/gis/django/contrib/gis/db/backend/postgis/__init__.py (modified) (1 diff)
- django/branches/gis/django/contrib/gis/db/backend/postgis/query.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) (10 diffs)
- django/branches/gis/django/contrib/gis/tests/geoapp/tests.py (modified) (1 diff)
- django/branches/gis/django/contrib/gis/utils/layermapping.py (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
django/branches/gis/django/contrib/gis/db/backend/__init__.py
r6919 r7028 6 6 7 7 (1) GeoBackEndField, a base class needed for GeometryField. 8 (2) GeometryProxy, for lazy-instantiated geometries from the 9 database output. 10 (3) GIS_TERMS, a list of acceptable geographic lookup types for 8 (2) GIS_TERMS, a list of acceptable geographic lookup types for 11 9 the backend. 12 ( 4) The `parse_lookup` function, used for spatial SQL construction by10 (3) The `parse_lookup` function, used for spatial SQL construction by 13 11 the GeoQuerySet. 14 ( 5) The `create_spatial_db`, and `get_geo_where_clause`12 (4) The `create_spatial_db`, and `get_geo_where_clause` 15 13 routines (needed by `parse_lookup`). 16 17 Currently only PostGIS is supported, but someday backends will be added for 18 additional spatial databases (e.g., Oracle, DB2). 14 (5) The `SpatialBackend` object, which contains information specific 15 to the spatial backend. 19 16 """ 20 17 from types import StringType, UnicodeType … … 27 24 28 25 # These routines (needed by GeoManager), default to False. 29 ASGML, ASKML, DISTANCE, TRANSFORM, UNION, VERSION = (False, False, False, False, False, False)26 ASGML, ASKML, DISTANCE, EXTENT, TRANSFORM, UNION, VERSION = (False, False, False, False, False, False, False) 30 27 31 28 if settings.DATABASE_ENGINE == 'postgresql_psycopg2': … … 35 32 PostGISField as GeoBackendField, POSTGIS_TERMS as GIS_TERMS, \ 36 33 create_spatial_db, get_geo_where_clause, \ 37 ASGML, ASKML, DISTANCE, GEOM_SELECT, TRANSFORM, UNION, \34 ASGML, ASKML, DISTANCE, EXTENT, GEOM_SELECT, TRANSFORM, UNION, \ 38 35 MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2 39 36 VERSION = (MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2) … … 55 52 else: 56 53 raise NotImplementedError('No Geographic Backend exists for %s' % settings.DATABASE_ENGINE) 54 55 class SpatialBackend(object): 56 "A container for properties of the Spatial Backend." 57 as_kml = ASKML 58 as_gml = ASGML 59 distance = DISTANCE 60 extent = EXTENT 61 name = SPATIAL_BACKEND 62 select = GEOM_SELECT 63 transform = TRANSFORM 64 union = UNION 65 version = VERSION 57 66 58 67 #### query.py overloaded functions #### django/branches/gis/django/contrib/gis/db/backend/postgis/__init__.py
r6886 r7028 7 7 get_geo_where_clause, GEOM_FUNC_PREFIX, POSTGIS_TERMS, \ 8 8 MAJOR_VERSION, MINOR_VERSION1, MINOR_VERSION2, \ 9 ASKML, ASGML, DISTANCE, GEOM_FROM_TEXT, UNION, TRANSFORM, GEOM_SELECT9 ASKML, ASGML, DISTANCE, EXTENT, GEOM_FROM_TEXT, UNION, TRANSFORM, GEOM_SELECT django/branches/gis/django/contrib/gis/db/backend/postgis/query.py
r6919 r7028 41 41 ASGML = get_func('AsGML') 42 42 DISTANCE = get_func('Distance') 43 EXTENT = get_func('extent') 43 44 GEOM_FROM_TEXT = get_func('GeomFromText') 44 45 GEOM_FROM_WKB = get_func('GeomFromWKB') django/branches/gis/django/contrib/gis/db/models/manager.py
r6886 r7028 11 11 return self.get_query_set().distance(*args, **kwargs) 12 12 13 def extent(self, *args, **kwargs): 14 return self.get_query_set().extent(*args, **kwargs) 15 13 16 def gml(self, *args, **kwargs): 14 17 return self.get_query_set().gml(*args, **kwargs) django/branches/gis/django/contrib/gis/db/models/query.py
r6966 r7028 7 7 from django.contrib.gis.db.models.fields import GeometryField 8 8 # parse_lookup depends on the spatial database backend. 9 from django.contrib.gis.db.backend import parse_lookup, \ 10 ASGML, ASKML, DISTANCE, GEOM_SELECT, SPATIAL_BACKEND, TRANSFORM, UNION, VERSION 9 from django.contrib.gis.db.backend import parse_lookup, SpatialBackend 11 10 from django.contrib.gis.geos import GEOSGeometry 12 11 13 12 # Shortcut booleans for determining the backend. 14 oracle = SPATIAL_BACKEND== 'oracle'15 postgis = S PATIAL_BACKEND== 'postgis'13 oracle = SpatialBackend.name == 'oracle' 14 postgis = SpatialBackend.name == 'postgis' 16 15 17 16 class GeoQ(Q): … … 24 23 class GeoQuerySet(QuerySet): 25 24 "Geographical-enabled QuerySet object." 26 25 27 26 #### Overloaded QuerySet Routines #### 28 27 def __init__(self, model=None): … … 38 37 # If GEOM_SELECT is defined in the backend, then it will be used 39 38 # for the selection format of the geometry column. 40 if GEOM_SELECT:39 if SpatialBackend.select: 41 40 # Transformed geometries in Oracle use EWKT so that the SRID 42 41 # on the transformed lazy geometries is set correctly). 43 self._geo_fmt = GEOM_SELECT42 self._geo_fmt = SpatialBackend.select 44 43 else: 45 44 self._geo_fmt = '%s' … … 260 259 GeoQuerySet. 261 260 """ 261 DISTANCE = SpatialBackend.distance 262 262 if not DISTANCE: 263 263 raise ImproperlyConfigured('Distance() stored proecedure not available.') … … 300 300 return self.extra(select=dist_select) 301 301 302 def extent(self, field_name=None): 303 """ 304 Returns the extent (aggregate) of the features in the GeoQuerySet. The 305 extent will be returned as a 4-tuple, consisting of (xmin, ymin, xmax, ymax). 306 """ 307 EXTENT = SpatialBackend.extent 308 if not EXTENT: 309 raise ImproperlyConfigured('Extent stored procedure not available.') 310 311 if not field_name: 312 field_name = self._get_geofield() 313 314 field_col = self._geo_column(field_name) 315 if not field_col: 316 raise TypeError('Extent information only available on GeometryFields.') 317 318 # Getting the SQL for the query. 319 try: 320 select, sql, params = self._get_sql_clause() 321 except EmptyResultSet: 322 return None 323 324 # Constructing the query that will select the extent. 325 extent_sql = ('SELECT %s(%s)' % (EXTENT, field_col)) + sql 326 327 # Getting a cursor, executing the query, and extracting the returned 328 # value from the extent function. 329 cursor = connection.cursor() 330 cursor.execute(extent_sql, params) 331 box = cursor.fetchone()[0] 332 333 if box: 334 # TODO: Parsing of BOX3D, Oracle support (patches welcome!) 335 # Box text will be something like "BOX(-90.0 30.0, -85.0 40.0)"; 336 # parsing out and returning as a 4-tuple. 337 ll, ur = box[4:-1].split(',') 338 xmin, ymin = map(float, ll.split()) 339 xmax, ymax = map(float, ur.split()) 340 return (xmin, ymin, xmax, ymax) 341 else: 342 return None 343 302 344 def gml(self, field_name=None, precision=8, version=2): 303 345 """ … … 306 348 """ 307 349 # Is GML output supported? 350 ASGML = SpatialBackend.as_gml 308 351 if not ASGML: 309 352 raise ImproperlyConfigured('AsGML() stored procedure not available.') … … 323 366 # PostGIS AsGML() aggregate function parameter order depends on the 324 367 # version -- uggh. 325 major, minor1, minor2 = VERSION368 major, minor1, minor2 = SpatialBackend.version 326 369 if major >= 1 and (minor1 > 3 or (minor1 == 3 and minor2 > 1)): 327 370 gml_select = {'gml':'%s(%s,%s,%s)' % (ASGML, version, field_col, precision)} … … 338 381 """ 339 382 # Is KML output supported? 383 ASKML = SpatialBackend.as_kml 340 384 if not ASKML: 341 385 raise ImproperlyConfigured('AsKML() stored procedure not available.') … … 376 420 # Setting the key for the field's column with the custom SELECT SQL to 377 421 # override the geometry column returned from the database. 422 TRANSFORM = SpatialBackend.transform 378 423 if oracle: 379 424 custom_sel = '%s(%s, %s)' % (TRANSFORM, col, srid) … … 392 437 """ 393 438 # Making sure backend supports the Union stored procedure 439 UNION = SpatialBackend.union 394 440 if not UNION: 395 441 raise ImproperlyConfigured('Union stored procedure not available.') django/branches/gis/django/contrib/gis/tests/geoapp/tests.py
r6979 r7028 172 172 self.assertAlmostEqual(ptown.x, p.point.x, prec) 173 173 self.assertAlmostEqual(ptown.y, p.point.y, prec) 174 175 @no_oracle # Most likely can do this in Oracle, however, it is not yet implemented (patches welcome!) 176 def test05_extent(self): 177 "Testing the extent() GeoManager method." 178 # Reference query: 179 # `SELECT ST_extent(point) FROM geoapp_city WHERE (name='Houston' or name='Dallas');` 180 # => BOX(-96.8016128540039 29.7633724212646,-95.3631439208984 32.7820587158203) 181 expected = (-96.8016128540039, 29.7633724212646, -95.3631439208984, 32.782058715820) 182 183 qs = City.objects.filter(name__in=('Houston', 'Dallas')) 184 extent = qs.extent() 185 186 for val, exp in zip(extent, expected): 187 self.assertAlmostEqual(exp, val, 8) 174 188 175 189 def test09_disjoint(self): django/branches/gis/django/contrib/gis/utils/layermapping.py
r7024 r7028 113 113 from django.core.exceptions import ObjectDoesNotExist 114 114 from django.contrib.gis.db.models.fields import GeometryField 115 from django.contrib.gis.db.backend import S PATIAL_BACKEND115 from django.contrib.gis.db.backend import SpatialBackend 116 116 from django.contrib.gis.gdal import CoordTransform, DataSource, \ 117 117 OGRException, OGRGeometry, OGRGeomType, SpatialReference … … 507 507 try: 508 508 db_table = self.model._meta.db_table 509 if S PATIAL_BACKEND== 'oracle': db_table = db_table.upper()509 if SpatialBackend.name == 'oracle': db_table = db_table.upper() 510 510 gc_kwargs = {GeometryColumns.table_name_col() : db_table} 511 511 return GeometryColumns.objects.get(**gc_kwargs)
