diff --git a/django/contrib/gis/db/backend/__init__.py b/django/contrib/gis/db/backend/__init__.py new file mode 100644 index 0000000000..ecf41e05ac --- /dev/null +++ b/django/contrib/gis/db/backend/__init__.py @@ -0,0 +1,24 @@ +from django.db import connection + +if hasattr(connection.ops, 'spatial_version'): + from warnings import warn + warn('The `django.contrib.gis.db.backend` module was refactored and ' + 'renamed to `django.contrib.gis.db.backends` in 1.2. ' + 'All functionality of `SpatialBackend` ' + 'has been moved to the `ops` attribute of the spatial database ' + 'backend. A `SpatialBackend` alias is provided here for ' + 'backwards-compatibility, but will be removed in 1.3.') + SpatialBackend = connection.ops + +from django.db import connection + +if hasattr(connection.ops, 'spatial_version'): + from warnings import warn + warn('The `django.contrib.gis.db.backend` module was refactored and ' + 'renamed to `django.contrib.gis.db.backends` in 1.2. ' + 'All functionality of `SpatialBackend` ' + 'has been moved to the `ops` attribute of the spatial database ' + 'backend. A `SpatialBackend` alias is provided here for ' + 'backwards-compatibility, but will be removed in 1.3.') + SpatialBackend = connection.ops + diff --git a/django/contrib/gis/db/backends/mysql/operations.py b/django/contrib/gis/db/backends/mysql/operations.py index 658aebe04e..1653636dd4 100644 --- a/django/contrib/gis/db/backends/mysql/operations.py +++ b/django/contrib/gis/db/backends/mysql/operations.py @@ -13,6 +13,7 @@ class MySQLOperations(DatabaseOperations, BaseSpatialOperations): from_text = 'GeomFromText' Adapter = WKTAdapter + Adaptor = Adapter # Backwards-compatibility alias. geometry_functions = { 'bbcontains' : 'MBRContains', # For consistency w/PostGIS API diff --git a/django/contrib/gis/db/backends/oracle/models.py b/django/contrib/gis/db/backends/oracle/models.py index 207c2ed41b..de757ffbec 100644 --- a/django/contrib/gis/db/backends/oracle/models.py +++ b/django/contrib/gis/db/backends/oracle/models.py @@ -18,7 +18,6 @@ class GeometryColumns(models.Model): srid = models.IntegerField(primary_key=True) # TODO: Add support for `diminfo` column (type MDSYS.SDO_DIM_ARRAY). class Meta: - app_label = 'gis' db_table = 'USER_SDO_GEOM_METADATA' managed = False @@ -54,7 +53,6 @@ class SpatialRefSys(models.Model, SpatialRefSysMixin): objects = models.GeoManager() class Meta: - app_label = 'gis' db_table = 'CS_SRS' managed = False diff --git a/django/contrib/gis/db/backends/oracle/operations.py b/django/contrib/gis/db/backends/oracle/operations.py index cf210274db..97f7b6c20b 100644 --- a/django/contrib/gis/db/backends/oracle/operations.py +++ b/django/contrib/gis/db/backends/oracle/operations.py @@ -75,6 +75,7 @@ class OracleOperations(DatabaseOperations, BaseSpatialOperations): valid_aggregates = dict([(a, None) for a in ('Union', 'Extent')]) Adapter = OracleSpatialAdapter + Adaptor = Adapter # Backwards-compatibility alias. area = 'SDO_GEOM.SDO_AREA' gml= 'SDO_UTIL.TO_GMLGEOMETRY' diff --git a/django/contrib/gis/db/backends/postgis/models.py b/django/contrib/gis/db/backends/postgis/models.py index 57d660d7c2..a38598343c 100644 --- a/django/contrib/gis/db/backends/postgis/models.py +++ b/django/contrib/gis/db/backends/postgis/models.py @@ -18,7 +18,6 @@ class GeometryColumns(models.Model): type = models.CharField(max_length=30) class Meta: - app_label = 'gis' db_table = 'geometry_columns' managed = False @@ -55,7 +54,6 @@ class SpatialRefSys(models.Model, SpatialRefSysMixin): proj4text = models.CharField(max_length=2048) class Meta: - app_label = 'gis' db_table = 'spatial_ref_sys' managed = False diff --git a/django/contrib/gis/db/backends/postgis/operations.py b/django/contrib/gis/db/backends/postgis/operations.py index ddf10de673..b1a9e31529 100644 --- a/django/contrib/gis/db/backends/postgis/operations.py +++ b/django/contrib/gis/db/backends/postgis/operations.py @@ -66,6 +66,7 @@ class PostGISOperations(DatabaseOperations, BaseSpatialOperations): ('Collect', 'Extent', 'Extent3D', 'MakeLine', 'Union')]) Adapter = PostGISAdapter + Adaptor = Adapter # Backwards-compatibility alias. def __init__(self, connection): super(PostGISOperations, self).__init__(connection) diff --git a/django/contrib/gis/db/backends/spatialite/models.py b/django/contrib/gis/db/backends/spatialite/models.py index 67a1c0b1d2..684c5d8fc7 100644 --- a/django/contrib/gis/db/backends/spatialite/models.py +++ b/django/contrib/gis/db/backends/spatialite/models.py @@ -16,7 +16,6 @@ class GeometryColumns(models.Model): spatial_index_enabled = models.IntegerField() class Meta: - app_label = 'gis' db_table = 'geometry_columns' managed = False @@ -57,6 +56,5 @@ class SpatialRefSys(models.Model, SpatialRefSysMixin): return SpatialReference(self.proj4text).wkt class Meta: - app_label = 'gis' db_table = 'spatial_ref_sys' managed = False diff --git a/django/contrib/gis/db/backends/spatialite/operations.py b/django/contrib/gis/db/backends/spatialite/operations.py index aeacde1a92..e6f8409fdb 100644 --- a/django/contrib/gis/db/backends/spatialite/operations.py +++ b/django/contrib/gis/db/backends/spatialite/operations.py @@ -55,6 +55,7 @@ class SpatiaLiteOperations(DatabaseOperations, BaseSpatialOperations): valid_aggregates = dict([(k, None) for k in ('Extent', 'Union')]) Adapter = SpatiaLiteAdapter + Adaptor = Adapter # Backwards-compatibility alias. area = 'Area' centroid = 'Centroid' diff --git a/django/contrib/gis/models.py b/django/contrib/gis/models.py index e69de29bb2..e379e82a7b 100644 --- a/django/contrib/gis/models.py +++ b/django/contrib/gis/models.py @@ -0,0 +1,9 @@ +from django.db import connection + +if (hasattr(connection.ops, 'spatial_version') and + not connection.ops.mysql): + # Getting the `SpatialRefSys` and `GeometryColumns` + # models for the default spatial backend. These + # aliases are provided for backwards-compatibility. + SpatialRefSys = connection.ops.spatial_ref_sys() + GeometryColumns = connection.ops.geometry_columns() diff --git a/docs/ref/contrib/gis/db-api.txt b/docs/ref/contrib/gis/db-api.txt index 0959156c43..6797ce2de0 100644 --- a/docs/ref/contrib/gis/db-api.txt +++ b/docs/ref/contrib/gis/db-api.txt @@ -23,13 +23,16 @@ its functionality into full-fledged spatial database backends: * :mod:`django.contrib.gis.db.backends.oracle` * :mod:`django.contrib.gis.db.backends.spatialite` -Backwards-Compatibility ------------------------ +Database Settings Backwards-Compatibility +----------------------------------------- -For those using the old database settings (e.g., the ``DATABASE_*`` settings) -Django 1.2 will automatically use the appropriate spatial backend as long -as :mod:`django.contrib.gis` is in your :setting:`INSTALLED_APPS`. For -example, if you have the following in your settings:: +In :ref:`Django 1.2 `, the way +to :ref:`specify databases ` in your settings was changed. +The old database settings format (e.g., the ``DATABASE_*`` settings) +is backwards compatible with GeoDjango, and will automatically use the +appropriate spatial backend as long as :mod:`django.contrib.gis` is in +your :setting:`INSTALLED_APPS`. For example, if you have the following in +your settings:: DATABASE_ENGINE='postgresql_psycopg2' @@ -41,9 +44,37 @@ example, if you have the following in your settings:: ... ) -Then, :mod:`django.contrib.gis.db.backends.postgis` will automatically be used as your +Then, :mod:`django.contrib.gis.db.backends.postgis` is automatically used as your spatial backend. +.. _mysql-spatial-limitations: + +MySQL Spatial Limitations +------------------------- + +MySQL's spatial extensions only support bounding box operations +(what MySQL calls minimum bounding rectangles, or MBR). Specifically, +`MySQL does not conform to the OGC standard `_: + + Currently, MySQL does not implement these functions + [``Contains``, ``Crosses``, ``Disjoint``, ``Intersects``, ``Overlaps``, + ``Touches``, ``Within``] + according to the specification. Those that are implemented return + the same result as the corresponding MBR-based functions. + +In other words, while spatial lookups such as :lookup:`contains ` +are available in GeoDjango when using MySQL, the results returned are really +equivalent to what would be returned when using :lookup:`bbcontains` +on a different spatial backend. + +.. warning:: + + True spatial indexes (R-trees) are only supported with + MyISAM tables on MySQL. [#fnmysqlidx]_ In other words, when using + MySQL spatial extensions you have to choose between fast spatial + lookups and the integrity of your data -- MyISAM tables do + not support transactions or foreign key constraints. + Creating and Saving Geographic Models ===================================== Here is an example of how to create a geometry object (assuming the ``Zipcode`` @@ -307,4 +338,12 @@ Method PostGIS Oracle SpatiaLite .. [#fngeojson] *See* Howard Butler, Martin Daly, Allan Doyle, Tim Schaub, & Christopher Schmidt, `The GeoJSON Format Specification `_, Revision 1.0 (June 16, 2008). .. [#fndistsphere14] *See* `PostGIS 1.4 documentation `_ on ``ST_distance_sphere``. .. [#fndistsphere15] *See* `PostGIS 1.5 documentation `_ on ``ST_distance_sphere``. -.. [#] MySQL only supports bounding box operations (known as minimum bounding rectangles, or MBR, in MySQL). Thus, spatial lookups such as :lookup:`contains ` are really equivalent to :lookup:`bbcontains`. +.. [#fnmysqlidx] *See* `Creating Spatial Indexes `_ + in the MySQL 5.1 Reference Manual: + + For MyISAM tables, ``SPATIAL INDEX`` creates an R-tree index. For storage + engines that support nonspatial indexing of spatial columns, the engine + creates a B-tree index. A B-tree index on spatial values will be useful + for exact-value lookups, but not for range scans. + +.. [#] Refer :ref:`mysql-spatial-limitations` section for more details. diff --git a/docs/ref/contrib/gis/install.txt b/docs/ref/contrib/gis/install.txt index 55883d8ba5..00d4e62e9f 100644 --- a/docs/ref/contrib/gis/install.txt +++ b/docs/ref/contrib/gis/install.txt @@ -150,13 +150,13 @@ directly from Python using ctypes. First, download GEOS 3.2 from the refractions website and untar the source archive:: - $ wget http://download.osgeo.org/geos/geos-3.2.1.tar.bz2 - $ tar xjf geos-3.2.1.tar.bz2 + $ wget http://download.osgeo.org/geos/geos-3.2.2.tar.bz2 + $ tar xjf geos-3.2.2.tar.bz2 Next, change into the directory where GEOS was unpacked, run the configure script, compile, and install:: - $ cd geos-3.2.1 + $ cd geos-3.2.2 $ ./configure $ make $ sudo make install @@ -273,9 +273,9 @@ supports :ref:`GDAL's vector data ` capabilities [#]_. First download the latest GDAL release version and untar the archive:: - $ wget http://download.osgeo.org/gdal/gdal-1.7.1.tar.gz - $ tar xzf gdal-1.7.1.tar.gz - $ cd gdal-1.7.1 + $ wget http://download.osgeo.org/gdal/gdal-1.7.2.tar.gz + $ tar xzf gdal-1.7.2.tar.gz + $ cd gdal-1.7.2 Configure, make and install:: @@ -516,9 +516,9 @@ user. For example, you can use the following to become the ``postgres`` user:: The location *and* name of the PostGIS SQL files (e.g., from ``POSTGIS_SQL_PATH`` below) depends on the version of PostGIS. - PostGIS versions 1.3 and below use ``/contrib/lwpostgis.sql``, whereas - versions 1.4 and 1.5 use ``/contrib/postgis-1.4/postgis.sql`` and - ``/contrib/postgis-1.5/postgis.sql``, respectively. + PostGIS versions 1.3 and below use ``/contrib/lwpostgis.sql``; + whereas version 1.4 uses ``/contrib/postgis.sql`` and + version 1.5 uses ``/contrib/postgis-1.5/postgis.sql``. The example below assumes PostGIS 1.5, thus you may need to modify ``POSTGIS_SQL_PATH`` and the name of the SQL file for the specific diff --git a/docs/releases/1.2.txt b/docs/releases/1.2.txt index 31b95e4ace..e8370c2b4b 100644 --- a/docs/releases/1.2.txt +++ b/docs/releases/1.2.txt @@ -77,6 +77,9 @@ changes: __members__ = property(lambda self: self.__dir__()) + +.. _specifying-databases: + Specifying databases -------------------- @@ -338,8 +341,6 @@ you need an unmodified instance of your model, you should pass a copy to the ``ModelForm`` constructor. -.. _deprecated-features-1.2: - ``BooleanField`` on MySQL -------------------------- @@ -350,6 +351,8 @@ people this shouldn't have been a problem because ``bool`` is a subclass of only time this should ever be an issue is if you were expecting printing the ``repr`` of a ``BooleanField`` to print ``1`` or ``0``. +.. _deprecated-features-1.2: + Features deprecated in 1.2 ========================== @@ -363,7 +366,7 @@ library, has been deprecated. If you are currently using the ``postgresql`` backend, you should migrate to using the ``postgresql_psycopg2`` backend. To update your code, install the ``psycopg2`` library and change the -``DATABASE_ENGINE`` setting to read ``postgresql_psycopg2``. +:setting:`DATABASE_ENGINE` setting to read ``postgresql_psycopg2``. CSRF response-rewriting middleware ---------------------------------- @@ -594,6 +597,88 @@ deprecated in favor of the new :ref:`Format localization information in a ``formats.py`` file in the corresponding ``django/conf/locale//`` directory. +GeoDjango +--------- + +To allow support for multiple databases, the GeoDjango database internals were +changed substantially. The largest backwards-incompatible change is that +the module ``django.contrib.gis.db.backend`` was renamed to +:mod:`django.contrib.gis.db.backends`, where the full-fledged +:ref:`spatial databased backends ` now exist. The +following sections provide information on the most-popular APIs that +were affected by these changes. + +``SpatialBackend`` +^^^^^^^^^^^^^^^^^^ + +Prior to the creation of the separate spatial backends, the +``django.contrib.gis.db.backend.SpatialBackend`` object was +provided as an abstraction to introspect on the capabilities of +the spatial database. All of the attributes and routines provided by +``SpatialBackend`` are now a part of the ``ops`` attribute of the +database backend. + +The old module ``django.contrib.gis.db.backend`` is still provided +for backwards-compatibility access to a ``SpatialBackend`` object, +which is just an alias to the ``ops`` module of the +*default* spatial database connection. + +Users that were relying on undocumented modules and objects +within ``django.contrib.gis.db.backend``, rather the abstractions +provided by ``SpatialBackend``, are required to modify their code. +For example, the following import which would work in 1.1 and +below:: + + from django.contrib.gis.db.backend.postgis import PostGISAdaptor + +Would need to be changed:: + + from django.db import connection + PostGISAdaptor = connection.ops.Adapter + +``SpatialRefSys`` and ``GeometryColumns`` models +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +In previous versions of GeoDjango, :mod:`django.contrib.gis.db.models` +had ``SpatialRefSys`` and ``GeometryColumns`` models for querying +the OGC spatial metadata tables ``spatial_ref_sys`` and ``geometry_columns``, +respectively. + +While these aliases are still provided, they are only for the +*default* database connection and exist only if the default connection +is using a supported spatial database backend. + +.. note:: + + Because the table structure of the OGC spatial metadata tables + differs across spatial databases, the ``SpatialRefSys`` and + ``GeometryColumns`` models can no longer be associated with + the ``gis`` application name. Thus, no models will be returned + when using the ``get_models`` method in the following example:: + + >>> from django.db.models import get_app, get_models + >>> get_models(get_app('gis')) + [] + +To get the correct ``SpatialRefSys`` and ``GeometryColumns`` +for your spatial database use the methods provided by the spatial backend:: + + >>> from django.db import connections + >>> SpatialRefSys = connections['my_spatialite'].ops.spatial_ref_sys() + >>> GeometryColumns = connections['my_postgis'].ops.geometry_columns() + +.. note:: + + When using the models returned from the ``spatial_ref_sys()`` and + ``geometry_columns()`` method, you'll still need to use the + correct database alias when querying on the non-default connection. + In other words, to ensure that the models in the example above + use the correct database:: + + sr_qs = SpatialRefSys.objects.using('my_spatialite').filter(...) + gc_qs = GeometryColumns.objects.using('my_postgis').filter(...) + + What's new in Django 1.2 ======================== @@ -793,6 +878,51 @@ The built-in :class:`~django.contrib.auth.models.User` model's :attr:`~django.contrib.auth.models.User.username` field now allows a wider range of characters, including ``@``, ``+``, ``.`` and ``-`` characters. +GeoDjango +--------- + +In 1.2, :ref:`GeoDjango ` was upgraded to provide +support for multiple spatial databases. As a result, the following +:ref:`spatial database backends ` +are now included: + +* :mod:`django.contrib.gis.db.backends.postgis` +* :mod:`django.contrib.gis.db.backends.mysql` +* :mod:`django.contrib.gis.db.backends.oracle` +* :mod:`django.contrib.gis.db.backends.spatialite` + +GeoDjango now supports the rich capabilities added +in the `PostGIS 1.5 release `_. +New features include suppport for the the :ref:`geography type ` +and enabling of :ref:`distance queries ` +with non-point geometries on geographic coordinate systems. + +Support for 3D geometry fields was added, and may be enabled +by setting the :attr:`~django.contrib.gis.db.models.GeometryField.dim` +keyword to 3 in your :class:`~django.contrib.gis.db.models.GeometryField`. +The :class:`~django.contrib.gis.db.models.Extent3D` aggregate +and :meth:`~django.contrib.gis.db.models.GeoQuerySet.extent3d` ``GeoQuerySet`` +method were added as a part of this feature. + +The following :class:`~django.contrib.gis.db.models.GeoQeurySet` +methods are new in 1.2: + +* :meth:`~django.contrib.gis.db.models.GeoQuerySet.force_rhr` +* :meth:`~django.contrib.gis.db.models.GeoQuerySet.reverse_geom` +* :meth:`~django.contrib.gis.db.models.GeoQuerySet.geohash` + +The :ref:`GEOS interface ` was updated to use +thread-safe C library functions when available on the platform. + +The :ref:`GDAL interface ` now allows the user to place +set a :attr:`~django.contrib.gis.gdal.Layer.spatial_filter` on +the features returned from a :class:`~django.contrib.gis.gdal.DataSource` +:class:`~django.contrib.gis.gdal.Layer`. + +Finally, :ref:`GeoDjango's documentation ` is now +included with Django's and is no longer +hosted separately at `geodjango.org `_. + Deprecation of old language code ``no`` ---------------------------------------