API базы данных GeoDjango

Пространственные бэкенды

В настоящее время GeoDjango предоставляет следующие бэкенды пространственных баз данных:

  • 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

Django поддерживает пространственные функции, оперирующие реальными геометриями, доступными в современных версиях MySQL. Однако пространственные функции не так богаты, как в других бэкендах, например, PostGIS.

Поддержка растровых изображений

RasterField в настоящее время реализована только для бэкенда PostGIS. Пространственный поиск доступен для растровых полей, но функции пространственной базы данных и агрегаты не реализованы для растровых полей.

Создание и сохранение моделей с полями геометрии

Приведем пример создания геометрического объекта (в предположении модели Zipcode):

>>> from zipcode.models import Zipcode
>>> z = Zipcode(code=77096, poly="POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")
>>> z.save()

Объекты GEOSGeometry также могут использоваться для сохранения геометрических моделей:

>>> 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()

Более того, если GEOSGeometry находится в другой системе координат (имеет другое значение SRID), чем поле, то он будет неявно преобразован в SRID поля модели с помощью процедуры transform пространственной базы данных:

>>> 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))

Таким образом, параметры геометрии могут быть переданы с помощью объекта GEOSGeometry, WKT (Well Known Text [1]), HEXEWKB (специфика PostGIS - геометрия WKB в шестнадцатеричном формате [2]) и GeoJSON (см. RFC 7946). По существу, если входные данные не являются объектом GEOSGeometry, поле геометрии попытается создать экземпляр GEOSGeometry из входных данных.

Подробнее о создании объектов GEOSGeometry см. в разделе GEOS tutorial.

Создание и сохранение моделей с растровыми полями

При создании растровых моделей поле raster будет неявно преобразовывать входные данные в GDALRaster с помощью ленивой оценки. Поэтому растровое поле будет принимать любой ввод, который принимается конструктором GDALRaster.

Приведем пример создания растрового объекта из растрового файла volcano.tif (в предположении модели Elevation):

>>> from elevation.models import Elevation
>>> dem = Elevation(name="Volcano", rast="/path/to/raster/volcano.tif")
>>> dem.save()

Объекты GDALRaster также могут использоваться для сохранения растровых моделей:

>>> 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()

Заметим, что это эквивалентно:

>>> dem = Elevation.objects.create(
...     name="Canyon",
...     rast={
...         "width": 10,
...         "height": 10,
...         "name": "Canyon",
...         "srid": 4326,
...         "scale": [0.1, -0.1],
...         "bands": [{"data": range(100)}],
...     },
... )

Пространственные поиски

Типы поиска GeoDjango могут использоваться с любым методом менеджера, например filter(), exclude() и т.д. Однако типы поиска, уникальные для GeoDjango, доступны только для пространственных полей.

Фильтры на «обычных» полях (например, CharField) могут быть объединены с фильтрами на географических полях. Географический поиск принимает геометрические и растровые данные с обеих сторон, и типы данных можно смешивать.

Ниже описана общая структура географических поисков. Полный справочник можно найти в разделе spatial lookup reference.

Геометрический поиск

Географические запросы с геометриями имеют следующий общий вид (в предположении, что модель Zipcode используется в API модели GeoDjango):

>>> qs = Zipcode.objects.filter(<field>__<lookup_type>=<parameter>)
>>> qs = Zipcode.objects.exclude(...)

Например:

>>> qs = Zipcode.objects.filter(poly__contains=pnt)
>>> qs = Elevation.objects.filter(poly__contains=rst)

В этом случае poly - географическое поле, contains - тип пространственного поиска, pnt - параметр (который может быть GEOSGeometry объектом или строкой GeoJSON , WKT или HEXEWKB), а rst - GDALRaster объектом.

Растровый поиск

Синтаксис поиска растра аналогичен синтаксису для геометрии. Единственное отличие заключается в том, что индекс полосы может быть указан в качестве дополнительного ввода. Если индекс полосы не указан, то по умолчанию используется первая полоса (индекс 0). В этом случае синтаксис идентичен синтаксису для поиска геометрии.

Чтобы указать индекс диапазона, дополнительный параметр может быть указан с обеих сторон поиска. С левой стороны для передачи индекса полосы используется синтаксис двойного подчеркивания. С правой стороны может быть указан кортеж из растра и индекса полосы.

Это приводит к следующей общей форме для поиска по растрам (в предположении, что модель Elevation используется в API модели GeoDjango):

>>> 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>)

Например:

>>> 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))

В левой части примера rast - поле географического растра, а contains - тип пространственного поиска. В правой части geom - это геометрический вход, а rst - объект GDALRaster. Индекс полосы по умолчанию равен 0 в первых двух запросах и установлен на 1 в остальных.

Хотя все пространственные поиски могут быть использованы с растровыми объектами с обеих сторон, не все базовые операторы изначально принимают растровые данные. В тех случаях, когда оператор ожидает ввода геометрии, растр автоматически преобразуется в геометрию. Важно помнить об этом при интерпретации результатов поиска.

Тип поддержки растров указан для всех поисков в compatibility table. В настоящее время поиск с использованием растров доступен только для бэкенда PostGIS.

Запросы о расстоянии

Вступление

Вычисление расстояний с помощью пространственных данных является сложной задачей, поскольку, к сожалению, Земля не плоская. Некоторые запросы о расстоянии с полями в географической системе координат, возможно, придется выражать по-другому из-за ограничений PostGIS. Более подробную информацию см. в разделе Выбор SRID в документации API модели GeoDjango.

Поиск расстояний

Доступность: PostGIS, MariaDB, MySQL, Oracle, SpatiaLite, PGRaster (Native)

Доступны следующие виды поиска расстояний:

Примечание

Для измерения, а не для запроса расстояний, используйте функцию Distance.

Для поиска расстояния используется кортеж параметров, состоящий из:

  1. Геометрия или растр для расчета; и
  2. Число или объект Distance, содержащий расстояние.

Если используется объект Distance, то он может быть выражен в любых единицах (генерируемый SQL будет использовать единицы, преобразованные в единицы поля); в противном случае предполагается, что числовые параметры выражены в единицах поля.

Примечание

В PostGIS ST_Distance_Sphere не ограничивает типы геометрии, с которыми выполняются запросы на географическое расстояние. [3] Однако эти запросы могут занять много времени, так как расстояния по большой окружности должны вычисляться на лету для каждой строки в запросе. Это происходит потому, что пространственный индекс для традиционных геометрических полей не может быть использован.

Для гораздо лучшей производительности при запросах расстояния WGS84, рассмотрите возможность использования geography columns в вашей базе данных вместо этого, потому что они могут использовать свой пространственный индекс в запросах расстояния. Вы можете указать GeoDjango использовать географический столбец, задав geography=True в определении вашего поля.

Например, допустим, у нас есть модель SouthTexasCity (из GeoDjango distance tests ) на проецируемой системе координат, действительной для городов в южном Техасе:

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)

Тогда запросы на расстояние могут быть выполнены следующим образом:

>>> 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)))

Растровые запросы работают аналогичным образом, заменяя поле геометрии point растровым полем, или объект pnt растровым объектом, или и тем, и другим. Для указания индекса диапазона растрового входа в правой части в поиск может быть передан 3-кортеж следующим образом:

>>> qs = SouthTexasCity.objects.filter(point__distance_gte=(rst, 2, D(km=7)))

Где полоса с индексом 2 (третья полоса) растра rst будет использоваться для поиска.

Таблицы совместимости

Пространственные поиски

В следующей таблице представлена сводная информация о том, какие пространственные поиски доступны для каждого бэкенда базы данных пространственных данных. Поиски PostGIS Raster (PGRaster) делятся на три категории, описанные в raster lookup details: «родная» поддержка N, двусторонняя «родная» поддержка B и поддержка преобразования геометрии C.

Тип поиска ПостГИС Oracle MariaDB MySQL [4] SpatiaLite PGRaster
bbcontains X   X X X N
bboverlaps X   X X X N
contained X   X X X N
contains X X X X X B
contains_properly X         B
coveredby X X     X B
covers X X     X B
crosses X   X X X C
disjoint X X X X X B
distance_gt X X X X X N
distance_gte X X X X X N
distance_lt X X X X X N
distance_lte X X X X X N
dwithin X X     X B
equals X X X X X C
exact X X X X X B
intersects X X X X X B
isempty X          
isvalid X X   X X  
overlaps X X X X X B
relate X X X   X C
same_as X X X X X B
touches X X X X X B
within X X X X X B
left X         C
right X         C
overlaps_left X         B
overlaps_right X         B
overlaps_above X         C
overlaps_below X         C
strictly_above X         C
strictly_below X         C

Функции базы данных

В следующей таблице приведено краткое описание функций базы данных, специфичных для географии, доступных в каждом пространственном бэкенде.

Функция ПостГИС Oracle MariaDB MySQL SpatiaLite
Area X X X X X
AsGeoJSON X X X X X
AsGML X X     X
AsKML X       X
AsSVG X       X
AsWKB X X X X X
AsWKT X X X X X
Azimuth X       X (LWGEOM/RTTOPO)
BoundingCircle X X      
Centroid X X X X X
ClosestPoint X       X
Difference X X X X X
Distance X X X X X
Envelope X X X X X
ForcePolygonCW X       X
FromWKB X X X X X
FromWKT X X X X X
GeoHash X     X X (LWGEOM/RTTOPO)
Intersection X X X X X
IsEmpty X        
IsValid X X   X X
Length X X X X X
LineLocatePoint X       X
MakeValid X       X (LWGEOM/RTTOPO)
MemSize X        
NumGeometries X X X X X
NumPoints X X X X X
Perimeter X X     X
PointOnSurface X X X   X
Reverse X X     X
Scale X       X
SnapToGrid X       X
SymDifference X X X X X
Transform X X     X
Translate X       X
Union X X X X X

Агрегатные функции

В следующей таблице приведена сводная информация о том, какие специфические для ГИС агрегатные функции доступны в каждом пространственном бэкенде. Обратите внимание, что MySQL не поддерживает ни один из этих агрегатов и поэтому исключен из таблицы.

A ПостГИС Oracle SpatiaLite
Collect X   X
Extent X X X
Extent3D X    
MakeLine X   X
Union X X X

Сноски

[1]См. Открытый геопространственный консорциум, Инк., OpenGIS Simple Feature Specification For SQL, Документ 99-049 (5 мая 1999 г.), в гл. 3.2.5, с. 3-11 (Текстовое представление геометрии на языке SQL).
[2]**Смотрите* PostGIS EWKB, EWKT и канонические формы, документация PostGIS в гл. 4.1.2.
[3]Смотрите Документацию PostGIS <https://postgis.net/docs/ST_DistanceSphere.html>`_ по ``ST_DistanceSphere.
[4]Более подробную информацию смотрите в разделе Пространственные ограничения MySQL.
Вернуться на верх