mirror of
				https://github.com/django/django.git
				synced 2025-10-28 16:16:12 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			460 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
			
		
		
	
	
			460 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			Plaintext
		
	
	
	
	
	
| ======================
 | |
| GeoDjango Database API
 | |
| ======================
 | |
| 
 | |
| .. _spatial-backends:
 | |
| 
 | |
| Spatial Backends
 | |
| ================
 | |
| 
 | |
| .. module:: django.contrib.gis.db.backends
 | |
|     :synopsis: GeoDjango's spatial database backends.
 | |
| 
 | |
| GeoDjango currently provides the following spatial database backends:
 | |
| 
 | |
| * ``django.contrib.gis.db.backends.postgis``
 | |
| * ``django.contrib.gis.db.backends.mysql``
 | |
| * ``django.contrib.gis.db.backends.oracle``
 | |
| * ``django.contrib.gis.db.backends.spatialite``
 | |
| 
 | |
| .. _mysql-spatial-limitations:
 | |
| 
 | |
| MySQL Spatial Limitations
 | |
| -------------------------
 | |
| 
 | |
| Django supports spatial functions operating on real geometries available in
 | |
| modern MySQL versions. However, the spatial functions are not as rich as other
 | |
| backends like PostGIS.
 | |
| 
 | |
| Raster Support
 | |
| --------------
 | |
| 
 | |
| ``RasterField`` is currently only implemented for the PostGIS backend. Spatial
 | |
| lookups are available for raster fields, but spatial database functions and
 | |
| aggregates aren't implemented for raster fields.
 | |
| 
 | |
| Creating and Saving Models with Geometry Fields
 | |
| ===============================================
 | |
| 
 | |
| Here is an example of how to create a geometry object (assuming the ``Zipcode``
 | |
| model):
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> from zipcode.models import Zipcode
 | |
|     >>> z = Zipcode(code=77096, poly="POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")
 | |
|     >>> z.save()
 | |
| 
 | |
| :class:`~django.contrib.gis.geos.GEOSGeometry` objects may also be used to save
 | |
| geometric models:
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> from django.contrib.gis.geos import GEOSGeometry
 | |
|     >>> poly = GEOSGeometry("POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")
 | |
|     >>> z = Zipcode(code=77096, poly=poly)
 | |
|     >>> z.save()
 | |
| 
 | |
| Moreover, if the ``GEOSGeometry`` is in a different coordinate system (has a
 | |
| different SRID value) than that of the field, then it will be implicitly
 | |
| transformed into the SRID of the model's field, using the spatial database's
 | |
| transform procedure:
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> poly_3084 = GEOSGeometry(
 | |
|     ...     "POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))", srid=3084
 | |
|     ... )  # SRID 3084 is 'NAD83(HARN) / Texas Centric Lambert Conformal'
 | |
|     >>> z = Zipcode(code=78212, poly=poly_3084)
 | |
|     >>> z.save()
 | |
|     >>> from django.db import connection
 | |
|     >>> print(
 | |
|     ...     connection.queries[-1]["sql"]
 | |
|     ... )  # printing the last SQL statement executed (requires DEBUG=True)
 | |
|     INSERT INTO "geoapp_zipcode" ("code", "poly") VALUES (78212, ST_Transform(ST_GeomFromWKB('\\001 ... ', 3084), 4326))
 | |
| 
 | |
| Thus, geometry parameters may be passed in using the ``GEOSGeometry`` object,
 | |
| WKT (Well Known Text [#fnwkt]_), HEXEWKB (PostGIS specific -- a WKB geometry in
 | |
| hexadecimal [#fnewkb]_), and GeoJSON (see :rfc:`7946`). Essentially, if the
 | |
| input is not a ``GEOSGeometry`` object, the geometry field will attempt to
 | |
| create a ``GEOSGeometry`` instance from the input.
 | |
| 
 | |
| For more information creating :class:`~django.contrib.gis.geos.GEOSGeometry`
 | |
| objects, refer to the :ref:`GEOS tutorial <geos-tutorial>`.
 | |
| 
 | |
| .. _creating-and-saving-raster-models:
 | |
| 
 | |
| Creating and Saving Models with Raster Fields
 | |
| =============================================
 | |
| 
 | |
| When creating raster models, the raster field will implicitly convert the input
 | |
| into a :class:`~django.contrib.gis.gdal.GDALRaster` using lazy-evaluation.
 | |
| The raster field will therefore accept any input that is accepted by the
 | |
| :class:`~django.contrib.gis.gdal.GDALRaster` constructor.
 | |
| 
 | |
| Here is an example of how to create a raster object from a raster file
 | |
| ``volcano.tif`` (assuming the ``Elevation`` model):
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> from elevation.models import Elevation
 | |
|     >>> dem = Elevation(name="Volcano", rast="/path/to/raster/volcano.tif")
 | |
|     >>> dem.save()
 | |
| 
 | |
| :class:`~django.contrib.gis.gdal.GDALRaster` objects may also be used to save
 | |
| raster models:
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> from django.contrib.gis.gdal import GDALRaster
 | |
|     >>> rast = GDALRaster(
 | |
|     ...     {
 | |
|     ...         "width": 10,
 | |
|     ...         "height": 10,
 | |
|     ...         "name": "Canyon",
 | |
|     ...         "srid": 4326,
 | |
|     ...         "scale": [0.1, -0.1],
 | |
|     ...         "bands": [{"data": range(100)}],
 | |
|     ...     }
 | |
|     ... )
 | |
|     >>> dem = Elevation(name="Canyon", rast=rast)
 | |
|     >>> dem.save()
 | |
| 
 | |
| Note that this equivalent to:
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> dem = Elevation.objects.create(
 | |
|     ...     name="Canyon",
 | |
|     ...     rast={
 | |
|     ...         "width": 10,
 | |
|     ...         "height": 10,
 | |
|     ...         "name": "Canyon",
 | |
|     ...         "srid": 4326,
 | |
|     ...         "scale": [0.1, -0.1],
 | |
|     ...         "bands": [{"data": range(100)}],
 | |
|     ...     },
 | |
|     ... )
 | |
| 
 | |
| .. _spatial-lookups-intro:
 | |
| 
 | |
| Spatial Lookups
 | |
| ===============
 | |
| 
 | |
| GeoDjango's lookup types may be used with any manager method like
 | |
| ``filter()``, ``exclude()``, etc. However, the lookup types unique to
 | |
| GeoDjango are only available on spatial fields.
 | |
| 
 | |
| Filters on 'normal' fields (e.g. :class:`~django.db.models.CharField`)
 | |
| may be chained with those on geographic fields. Geographic lookups accept
 | |
| geometry and raster input on both sides and input types can be mixed freely.
 | |
| 
 | |
| The general structure of geographic lookups is described below. A complete
 | |
| reference can be found in the :ref:`spatial lookup reference<spatial-lookups>`.
 | |
| 
 | |
| Geometry Lookups
 | |
| ----------------
 | |
| 
 | |
| Geographic queries with geometries take the following general form (assuming
 | |
| the ``Zipcode`` model used in the :doc:`/ref/contrib/gis/model-api`):
 | |
| 
 | |
| .. code-block:: text
 | |
| 
 | |
|     >>> qs = Zipcode.objects.filter(<field>__<lookup_type>=<parameter>)
 | |
|     >>> qs = Zipcode.objects.exclude(...)
 | |
| 
 | |
| For example:
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> qs = Zipcode.objects.filter(poly__contains=pnt)
 | |
|     >>> qs = Elevation.objects.filter(poly__contains=rst)
 | |
| 
 | |
| In this case, ``poly`` is the geographic field,
 | |
| :lookup:`contains <gis-contains>` is the spatial lookup type, ``pnt`` is the
 | |
| parameter (which may be a :class:`~django.contrib.gis.geos.GEOSGeometry` object
 | |
| or a string of GeoJSON , WKT, or HEXEWKB), and ``rst`` is a
 | |
| :class:`~django.contrib.gis.gdal.GDALRaster` object.
 | |
| 
 | |
| .. _spatial-lookup-raster:
 | |
| 
 | |
| Raster Lookups
 | |
| --------------
 | |
| 
 | |
| The raster lookup syntax is similar to the syntax for geometries. The only
 | |
| difference is that a band index can be specified as additional input. If no
 | |
| band index is specified, the first band is used by default (index ``0``). In
 | |
| that case the syntax is identical to the syntax for geometry lookups.
 | |
| 
 | |
| To specify the band index, an additional parameter can be specified on both
 | |
| sides of the lookup. On the left hand side, the double underscore syntax is
 | |
| used to pass a band index. On the right hand side, a tuple of the raster and
 | |
| band index can be specified.
 | |
| 
 | |
| This results in the following general form for lookups involving rasters
 | |
| (assuming the ``Elevation`` model used in the
 | |
| :doc:`/ref/contrib/gis/model-api`):
 | |
| 
 | |
| .. code-block:: text
 | |
| 
 | |
|     >>> qs = Elevation.objects.filter(<field>__<lookup_type>=<parameter>)
 | |
|     >>> qs = Elevation.objects.filter(<field>__<band_index>__<lookup_type>=<parameter>)
 | |
|     >>> qs = Elevation.objects.filter(<field>__<lookup_type>=(<raster_input, <band_index>)
 | |
| 
 | |
| For example:
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> qs = Elevation.objects.filter(rast__contains=geom)
 | |
|     >>> qs = Elevation.objects.filter(rast__contains=rst)
 | |
|     >>> qs = Elevation.objects.filter(rast__1__contains=geom)
 | |
|     >>> qs = Elevation.objects.filter(rast__contains=(rst, 1))
 | |
|     >>> qs = Elevation.objects.filter(rast__1__contains=(rst, 1))
 | |
| 
 | |
| On the left hand side of the example, ``rast`` is the geographic raster field
 | |
| and :lookup:`contains <gis-contains>` is the spatial lookup type. On the right
 | |
| hand side, ``geom`` is a geometry input and ``rst`` is a
 | |
| :class:`~django.contrib.gis.gdal.GDALRaster` object. The band index defaults to
 | |
| ``0`` in the first two queries and is set to ``1`` on the others.
 | |
| 
 | |
| While all spatial lookups can be used with raster objects on both sides, not
 | |
| all underlying operators natively accept raster input. For cases where the
 | |
| operator expects geometry input, the raster is automatically converted to a
 | |
| geometry. It's important to keep this in mind when interpreting the lookup
 | |
| results.
 | |
| 
 | |
| The type of raster support is listed for all lookups in the :ref:`compatibility
 | |
| table <spatial-lookup-compatibility>`. Lookups involving rasters are currently
 | |
| only available for the PostGIS backend.
 | |
| 
 | |
| .. _distance-queries:
 | |
| 
 | |
| Distance Queries
 | |
| ================
 | |
| 
 | |
| Introduction
 | |
| ------------
 | |
| 
 | |
| Distance calculations with spatial data is tricky because, unfortunately, the
 | |
| Earth is not flat. Some distance queries with fields in a geographic coordinate
 | |
| system may have to be expressed differently because of limitations in PostGIS.
 | |
| Please see the :ref:`selecting-an-srid` section for more details.
 | |
| 
 | |
| .. _distance-lookups-intro:
 | |
| 
 | |
| Distance Lookups
 | |
| ----------------
 | |
| 
 | |
| *Availability*: PostGIS, MariaDB, MySQL, Oracle, SpatiaLite, PGRaster (Native)
 | |
| 
 | |
| The following distance lookups are available:
 | |
| 
 | |
| * :lookup:`distance_lt`
 | |
| * :lookup:`distance_lte`
 | |
| * :lookup:`distance_gt`
 | |
| * :lookup:`distance_gte`
 | |
| * :lookup:`dwithin` (except MariaDB and MySQL)
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     For *measuring*, rather than querying on distances, use the
 | |
|     :class:`~django.contrib.gis.db.models.functions.Distance` function.
 | |
| 
 | |
| Distance lookups take a tuple parameter comprising:
 | |
| 
 | |
| #. A geometry or raster to base calculations from; and
 | |
| #. A number or :class:`~django.contrib.gis.measure.Distance` object containing
 | |
|    the distance.
 | |
| 
 | |
| If a :class:`~django.contrib.gis.measure.Distance` object is used,
 | |
| it may be expressed in any units (the SQL generated will use units
 | |
| converted to those of the field); otherwise, numeric parameters are assumed
 | |
| to be in the units of the field.
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|     In PostGIS, ``ST_Distance_Sphere`` does *not* limit the geometry types
 | |
|     geographic distance queries are performed with. [#fndistsphere15]_
 | |
|     However, these queries may take a long time, as great-circle distances must
 | |
|     be calculated on the fly for *every* row in the query. This is because the
 | |
|     spatial index on traditional geometry fields cannot be used.
 | |
| 
 | |
|     For much better performance on WGS84 distance queries, consider using
 | |
|     :ref:`geography columns <geography-type>` in your database instead because
 | |
|     they are able to use their spatial index in distance queries.
 | |
|     You can tell GeoDjango to use a geography column by setting
 | |
|     ``geography=True`` in your field definition.
 | |
| 
 | |
| For example, let's say we have a ``SouthTexasCity`` model (from the
 | |
| :source:`GeoDjango distance tests <tests/gis_tests/distapp/models.py>` ) on a
 | |
| *projected* coordinate system valid for cities in southern Texas::
 | |
| 
 | |
|     from django.contrib.gis.db import models
 | |
| 
 | |
| 
 | |
|     class SouthTexasCity(models.Model):
 | |
|         name = models.CharField(max_length=30)
 | |
|         # A projected coordinate system (only valid for South Texas!)
 | |
|         # is used, units are in meters.
 | |
|         point = models.PointField(srid=32140)
 | |
| 
 | |
| Then distance queries may be performed as follows:
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> from django.contrib.gis.geos import GEOSGeometry
 | |
|     >>> from django.contrib.gis.measure import D  # ``D`` is a shortcut for ``Distance``
 | |
|     >>> from geoapp.models import SouthTexasCity
 | |
|     # Distances will be calculated from this point, which does not have to be projected.
 | |
|     >>> pnt = GEOSGeometry("POINT(-96.876369 29.905320)", srid=4326)
 | |
|     # If numeric parameter, units of field (meters in this case) are assumed.
 | |
|     >>> qs = SouthTexasCity.objects.filter(point__distance_lte=(pnt, 7000))
 | |
|     # Find all Cities within 7 km, > 20 miles away, and > 100 chains away (an obscure unit)
 | |
|     >>> qs = SouthTexasCity.objects.filter(point__distance_lte=(pnt, D(km=7)))
 | |
|     >>> qs = SouthTexasCity.objects.filter(point__distance_gte=(pnt, D(mi=20)))
 | |
|     >>> qs = SouthTexasCity.objects.filter(point__distance_gte=(pnt, D(chain=100)))
 | |
| 
 | |
| Raster queries work the same way by replacing the geometry field ``point`` with
 | |
| a raster field, or the ``pnt`` object with a raster object, or both. To specify
 | |
| the band index of a raster input on the right hand side, a 3-tuple can be
 | |
| passed to the lookup as follows:
 | |
| 
 | |
| .. code-block:: pycon
 | |
| 
 | |
|     >>> qs = SouthTexasCity.objects.filter(point__distance_gte=(rst, 2, D(km=7)))
 | |
| 
 | |
| Where the band with index 2 (the third band) of the raster ``rst`` would be
 | |
| used for the lookup.
 | |
| 
 | |
| .. _compatibility-table:
 | |
| 
 | |
| Compatibility Tables
 | |
| ====================
 | |
| 
 | |
| .. _spatial-lookup-compatibility:
 | |
| 
 | |
| Spatial Lookups
 | |
| ---------------
 | |
| 
 | |
| The following table provides a summary of what spatial lookups are available
 | |
| for each spatial database backend. The PostGIS Raster (PGRaster) lookups are
 | |
| divided into the three categories described in the :ref:`raster lookup details
 | |
| <spatial-lookup-raster>`: native support ``N``, bilateral native support ``B``,
 | |
| and geometry conversion support ``C``.
 | |
| 
 | |
| =================================  =========  ========= ============ ============ ========== ========
 | |
| Lookup Type                        PostGIS    Oracle    MariaDB      MySQL [#]_   SpatiaLite PGRaster
 | |
| =================================  =========  ========= ============ ============ ========== ========
 | |
| :lookup:`bbcontains`               X                    X            X            X          N
 | |
| :lookup:`bboverlaps`               X                    X            X            X          N
 | |
| :lookup:`contained`                X                    X            X            X          N
 | |
| :lookup:`contains <gis-contains>`  X          X         X            X            X          B
 | |
| :lookup:`contains_properly`        X                                                         B
 | |
| :lookup:`coveredby`                X          X         X (≥ 12.0.1) X            X          B
 | |
| :lookup:`covers`                   X          X                      X            X          B
 | |
| :lookup:`crosses`                  X                    X            X            X          C
 | |
| :lookup:`disjoint`                 X          X         X            X            X          B
 | |
| :lookup:`distance_gt`              X          X         X            X            X          N
 | |
| :lookup:`distance_gte`             X          X         X            X            X          N
 | |
| :lookup:`distance_lt`              X          X         X            X            X          N
 | |
| :lookup:`distance_lte`             X          X         X            X            X          N
 | |
| :lookup:`dwithin`                  X          X                                   X          B
 | |
| :lookup:`equals`                   X          X         X            X            X          C
 | |
| :lookup:`exact <same_as>`          X          X         X            X            X          B
 | |
| :lookup:`geom_type`                X          X (≥ 23c) X            X            X
 | |
| :lookup:`intersects`               X          X         X            X            X          B
 | |
| :lookup:`isempty`                  X                                              X
 | |
| :lookup:`isvalid`                  X          X         X (≥ 12.0.1) X            X
 | |
| :lookup:`overlaps`                 X          X         X            X            X          B
 | |
| :lookup:`relate`                   X          X         X                         X          C
 | |
| :lookup:`same_as`                  X          X         X            X            X          B
 | |
| :lookup:`touches`                  X          X         X            X            X          B
 | |
| :lookup:`within`                   X          X         X            X            X          B
 | |
| :lookup:`left`                     X                                                         C
 | |
| :lookup:`right`                    X                                                         C
 | |
| :lookup:`overlaps_left`            X                                                         B
 | |
| :lookup:`overlaps_right`           X                                                         B
 | |
| :lookup:`overlaps_above`           X                                                         C
 | |
| :lookup:`overlaps_below`           X                                                         C
 | |
| :lookup:`strictly_above`           X                                                         C
 | |
| :lookup:`strictly_below`           X                                                         C
 | |
| =================================  =========  ========= ============ ============ ========== ========
 | |
| 
 | |
| .. _database-functions-compatibility:
 | |
| 
 | |
| Database functions
 | |
| ------------------
 | |
| 
 | |
| The following table provides a summary of what geography-specific database
 | |
| functions are available on each spatial backend.
 | |
| 
 | |
| .. currentmodule:: django.contrib.gis.db.models.functions
 | |
| 
 | |
| ====================================  =======  ============== ============ =========== =================
 | |
| Function                              PostGIS  Oracle         MariaDB      MySQL       SpatiaLite
 | |
| ====================================  =======  ============== ============ =========== =================
 | |
| :class:`Area`                         X        X              X            X           X
 | |
| :class:`AsGeoJSON`                    X        X              X            X           X
 | |
| :class:`AsGML`                        X        X                                       X
 | |
| :class:`AsKML`                        X                                                X
 | |
| :class:`AsSVG`                        X                                                X
 | |
| :class:`AsWKB`                        X        X              X            X           X
 | |
| :class:`AsWKT`                        X        X              X            X           X
 | |
| :class:`Azimuth`                      X                                                X (LWGEOM/RTTOPO)
 | |
| :class:`BoundingCircle`               X        X                                       X (≥ 5.1)
 | |
| :class:`Centroid`                     X        X              X            X           X
 | |
| :class:`ClosestPoint`                 X                                                X
 | |
| :class:`Difference`                   X        X              X            X           X
 | |
| :class:`Distance`                     X        X              X            X           X
 | |
| :class:`Envelope`                     X        X              X            X           X
 | |
| :class:`ForcePolygonCW`               X                                                X
 | |
| :class:`FromWKB`                      X        X              X            X           X
 | |
| :class:`FromWKT`                      X        X              X            X           X
 | |
| :class:`GeoHash`                      X                       X (≥ 12.0.1) X           X (LWGEOM/RTTOPO)
 | |
| :class:`GeometryDistance`             X
 | |
| :class:`GeometryType`                 X        X (≥ 23c)      X            X           X
 | |
| :class:`Intersection`                 X        X              X            X           X
 | |
| :class:`IsEmpty`                      X                                                X
 | |
| :class:`IsValid`                      X        X              X (≥ 12.0.1) X           X
 | |
| :class:`Length`                       X        X              X            X           X
 | |
| :class:`LineLocatePoint`              X                                                X
 | |
| :class:`MakeValid`                    X                                                X (LWGEOM/RTTOPO)
 | |
| :class:`MemSize`                      X
 | |
| :class:`NumGeometries`                X        X              X            X           X
 | |
| :class:`NumPoints`                    X        X              X            X           X
 | |
| :class:`Perimeter`                    X        X                                       X
 | |
| :class:`PointOnSurface`               X        X              X                        X
 | |
| :class:`Reverse`                      X        X                                       X
 | |
| :class:`Rotate`                       X
 | |
| :class:`Scale`                        X                                                X
 | |
| :class:`SnapToGrid`                   X                                                X
 | |
| :class:`SymDifference`                X        X              X            X           X
 | |
| :class:`Transform`                    X        X                                       X
 | |
| :class:`Translate`                    X                                                X
 | |
| :class:`Union`                        X        X              X            X           X
 | |
| ====================================  =======  ============== ============ =========== =================
 | |
| 
 | |
| Aggregate Functions
 | |
| -------------------
 | |
| 
 | |
| The following table provides a summary of what GIS-specific aggregate functions
 | |
| are available on each spatial backend.
 | |
| 
 | |
| .. currentmodule:: django.contrib.gis.db.models
 | |
| 
 | |
| =======================  =======  ====== ============ ============  ==========
 | |
| Aggregate                PostGIS  Oracle MariaDB      MySQL         SpatiaLite
 | |
| =======================  =======  ====== ============ ============  ==========
 | |
| :class:`Collect`         X               X (≥ 12.0.1) X (≥ 8.0.24)  X
 | |
| :class:`Extent`          X        X                                 X
 | |
| :class:`Extent3D`        X
 | |
| :class:`MakeLine`        X                                          X
 | |
| :class:`Union`           X        X                                 X
 | |
| =======================  =======  ====== ============ ============  ==========
 | |
| 
 | |
| .. rubric:: Footnotes
 | |
| .. [#fnwkt] *See* Open Geospatial Consortium, Inc., `OpenGIS Simple Feature Specification For SQL <https://portal.ogc.org/files/?artifact_id=829>`_, Document 99-049 (May 5, 1999), at  Ch. 3.2.5, p. 3-11 (SQL Textual Representation of Geometry).
 | |
| .. [#fnewkb] *See* `PostGIS EWKB, EWKT and Canonical Forms <https://postgis.net/docs/using_postgis_dbmanagement.html#EWKB_EWKT>`_, PostGIS documentation at Ch. 4.1.2.
 | |
| .. [#fndistsphere15] *See* `PostGIS documentation <https://postgis.net/docs/ST_DistanceSphere.html>`_ on ``ST_DistanceSphere``.
 | |
| .. [#] Refer :ref:`mysql-spatial-limitations` section for more details.
 |