diff --git a/django/contrib/gis/db/backend/spatialite/models.py b/django/contrib/gis/db/backend/spatialite/models.py index 330a90c8be..e026f5de22 100644 --- a/django/contrib/gis/db/backend/spatialite/models.py +++ b/django/contrib/gis/db/backend/spatialite/models.py @@ -48,6 +48,11 @@ class SpatialRefSys(models.Model): ref_sys_name = models.CharField(max_length=256) proj4text = models.CharField(max_length=2048) + @property + def wkt(self): + from django.contrib.gis.gdal import SpatialReference + return SpatialReference(self.proj4text).wkt + class Meta: abstract = True db_table = 'spatial_ref_sys' diff --git a/django/contrib/gis/db/models/fields/__init__.py b/django/contrib/gis/db/models/fields/__init__.py index b108c16b00..b2dacc85d7 100644 --- a/django/contrib/gis/db/models/fields/__init__.py +++ b/django/contrib/gis/db/models/fields/__init__.py @@ -4,18 +4,30 @@ from django.contrib.gis.db.backend import SpatialBackend, gqn # GeometryProxy, GEOS, and Distance imports. from django.contrib.gis.db.models.proxy import GeometryProxy from django.contrib.gis.measure import Distance -# The `get_srid_info` function gets SRID information from the spatial -# reference system table w/o using the ORM. -from django.contrib.gis.models import get_srid_info - -def deprecated_property(func): - from warnings import warn - warn('This attribute has been deprecated, please use "%s" instead.' % func.__name__[1:]) - return property(func) # Local cache of the spatial_ref_sys table, which holds static data. # This exists so that we don't have to hit the database each time. -SRID_CACHE = {} +_srid_cache = {} + +def get_srid_info(srid): + """ + Returns the units, unit name, and spheroid WKT associated with the + given SRID from the `spatial_ref_sys` (or equivalent) spatial database + table. These results are cached. + """ + global _srid_cache + + if SpatialBackend.mysql: + return None, None, None + + if not srid in _srid_cache: + from django.contrib.gis.models import SpatialRefSys + sr = SpatialRefSys.objects.get(srid=srid) + units, units_name = sr.units + spheroid = SpatialRefSys.get_spheroid(sr.wkt) + _srid_cache[srid] = (units, units_name, spheroid) + + return _srid_cache[srid] class GeometryField(SpatialBackend.Field): "The base GIS field -- maps to the OpenGIS Specification Geometry type." @@ -51,9 +63,6 @@ class GeometryField(SpatialBackend.Field): # easily available in the field instance for distance queries. self.srid = srid - # units_cache, units_name_cache and _spheroid_cache are lazily loaded. - self._units_cache = self._units_name_cache = self._spheroid_cache = None - # Setting the dimension of the geometry field. self.dim = dim @@ -63,28 +72,29 @@ class GeometryField(SpatialBackend.Field): super(GeometryField, self).__init__(**kwargs) # Calling the parent initializtion function - def _populate_srid_info(self): - if self.srid not in SRID_CACHE: - SRID_CACHE[self.srid] = get_srid_info(self.srid) - self._units_cache, self._units_name_cache, self._spheroid_cache = SRID_CACHE[self.srid] + # The following properties are used to get the units, their name, and + # the spheroid corresponding to the SRID of the GeometryField. + def _get_srid_info(self): + # Get attributes from `get_srid_info`. + self._units, self._units_name, self._spheroid = get_srid_info(self.srid) - def _get_units(self): - if self._units_cache is None: - self._populate_srid_info() - return self._units_cache - units = property(_get_units) + @property + def spheroid(self): + if not hasattr(self, '_spheroid'): + self._get_srid_info() + return self._spheroid - def _get_units_name(self): - if self._units_name_cache is None: - self._populate_srid_info() - return self._units_name_cache - units_name = property(_get_units_name) + @property + def units(self): + if not hasattr(self, '_units'): + self._get_srid_info() + return self._units - def _get_spheroid(self): - if self._spheroid_cache is None: - self._populate_srid_info() - return self._spheroid_cache - _spheroid = property(_get_spheroid) + @property + def units_name(self): + if not hasattr(self, '_units_name'): + self._get_srid_info() + return self._units_name # The following properties are for formerly private variables that are now # public for GeometryField. Because of their use by third-party applications, diff --git a/django/contrib/gis/db/models/query.py b/django/contrib/gis/db/models/query.py index 25ea1aca71..3d31f73c29 100644 --- a/django/contrib/gis/db/models/query.py +++ b/django/contrib/gis/db/models/query.py @@ -4,10 +4,9 @@ from django.db.models.query import QuerySet, Q, ValuesQuerySet, ValuesListQueryS from django.contrib.gis.db.backend import SpatialBackend from django.contrib.gis.db.models import aggregates -from django.contrib.gis.db.models.fields import GeometryField, PointField +from django.contrib.gis.db.models.fields import get_srid_info, GeometryField, PointField from django.contrib.gis.db.models.sql import AreaField, DistanceField, GeomField, GeoQuery, GeoWhereNode from django.contrib.gis.measure import Area, Distance -from django.contrib.gis.models import get_srid_info class GeoQuerySet(QuerySet): "The Geographic QuerySet." diff --git a/django/contrib/gis/models.py b/django/contrib/gis/models.py index ca27c8821f..e24ca8e3e1 100644 --- a/django/contrib/gis/models.py +++ b/django/contrib/gis/models.py @@ -214,14 +214,6 @@ class SpatialRefSysMixin(object): except: return unicode(self.wkt) -# Defining dummy default first; if spatial db, will overrride. -def get_srid_info(srid): - """ - Dummy routine for the backends that do not have the OGC required - spatial metadata tables (like MySQL). - """ - return None, None, None - # Django test suite on 2.3 platforms will choke on code inside this # conditional. if not PYTHON23: @@ -237,62 +229,5 @@ if not PYTHON23: class SpatialRefSys(SpatialBackend.SpatialRefSys, SpatialRefSysMixin): pass GeometryColumns = SpatialBackend.GeometryColumns - - # Override `get_srid_info` with something real thing. - def get_srid_info(srid): - """ - Returns the units, unit name, and spheroid WKT associated with the - given SRID from the `spatial_ref_sys` (or equivalent) spatial database - table. We use a database cursor to execute the query because this - function is used when it is not possible to use the ORM (for example, - during field initialization). - """ - # SRID=-1 is a common convention for indicating the geometry has no - # spatial reference information associated with it. Thus, we will - # return all None values without raising an exception. - if srid == -1: return None, None, None - - # Getting the spatial reference WKT associated with the SRID from the - # `spatial_ref_sys` (or equivalent) spatial database table. This query - # cannot be executed using the ORM because this information is needed - # when the ORM cannot be used (e.g., during the initialization of - # `GeometryField`). - from django.db import connection - cur = connection.cursor() - qn = connection.ops.quote_name - stmt = 'SELECT %(table)s.%(wkt_col)s FROM %(table)s WHERE (%(table)s.%(srid_col)s = %(srid)s)' - params = {'table' : qn(SpatialRefSys._meta.db_table), - 'srid_col' : qn('srid'), - 'srid' : srid, - } - if SpatialBackend.spatialite: - if not HAS_GDAL: raise Exception('GDAL is required to use the SpatiaLite backend.') - params['wkt_col'] = 'proj4text' - else: - params['wkt_col'] = qn(SpatialRefSys.wkt_col()) - - # Executing the SQL statement. - cur.execute(stmt % params) - - # Fetching the WKT from the cursor; if the query failed raise an Exception. - fetched = cur.fetchone() - if not fetched: - raise ValueError('Failed to find spatial reference entry in "%s" corresponding to SRID=%s.' % - (SpatialRefSys._meta.db_table, srid)) - - if SpatialBackend.spatialite: - # Because the `spatial_ref_sys` table does _not_ contain a WKT column, - # we have to use GDAL to determine the units from the PROJ.4 string. - srs_wkt = SpatialReference(fetched[0]).wkt - else: - srs_wkt = fetched[0] - connection.close() - - # Getting metadata associated with the spatial reference system identifier. - # Specifically, getting the unit information and spheroid information - # (both required for distance queries). - unit, unit_name = SpatialRefSys.get_units(srs_wkt) - spheroid = SpatialRefSys.get_spheroid(srs_wkt) - return unit, unit_name, spheroid except: pass