GeoDjango База данных API
Пространственные бэкенды
GeoDjango в настоящее время предоставляет следующие пространственные бэкенды базы данных:
django.contrib.gis.db.backends.postgisdjango.contrib.gis.db.backends.mysqldjango.contrib.gis.db.backends.oracledjango.contrib.gis.db.backends.spatialite
Ограничения MySQL пространственного расширения
Пространственные расширения MySQL поддерживают только операции с ограничивающей рамкой (то, что MySQL называет минимальными ограничивающими прямоугольниками, или MBR). В частности, MySQL не соответствует стандарту OGC:
В настоящее время MySQL не реализует эти функции [Contains, Crosses, Disjoint, Intersects, Overlaps, Touches, Within] в соответствии со спецификацией. Реализованные функции возвращают тот же результат, что и соответствующие функции, основанные на MBR. Другими словами, хотя пространственные запросы, такие как contains доступны в GeoDjango при использовании MySQL, возвращаемые результаты фактически эквивалентны результатам, которые были бы возвращены при использовании bbcontains в другом пространственном бэкенде.
Предупреждение
Истинные пространственные индексы (R-деревья) поддерживаются только с таблицами MyISAM в MySQL. [5] Другими словами, при использовании пространственных расширений MySQL вам нужно выбирать между быстрыми пространственными запросами и целостностью ваших данных – таблицы MyISAM не поддерживают транзакции или ограничения внешних ключей.
Поддержка растровых данных
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 поля модели с использованием процедуры преобразования пространственной базы данных:
>>> 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 (Хорошо известный текст [1]), HEXEWKB (специфичный для PostGIS – геометрия WKB в шестнадцатеричном формате [2]) и GeoJSON [3]. По сути, если вход не является объектом GEOSGeometry, поле геометрии попытается создать экземпляр GEOSGeometry из входящих данных.
Дополнительную информацию о создании объектов GEOSGeometry см. в Руководство по GEOS.
Создание и сохранение моделей с растровыми полями
При создании растровых моделей растровое поле неявно преобразует вход в 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)}]},
... )
Пространственные запросы
Типы lookups GeoDjango могут использоваться с любыми методами менеджера, такими как filter(), exclude(), и т. д. Однако уникальные типы lookups GeoDjango доступны только для пространственных полей.
Фильтры по «обычным» полям (например, CharField) могут быть объединены с фильтрами по географическим полям. Географические запросы принимают геометрические и растровые данные с обеих сторон, и типы данных могут свободно комбинироваться.
Общая структура географических запросов описана ниже. Полная справка приведена в справке по пространственным запросам.
Геометрические запросы
Географические запросы с геометриями имеют следующий общий вид (предполагается модель 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 используемая в GeoDjango Модельный API):
>>> 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 в остальных.
Хотя все пространственные запросы могут использоваться с растровыми объектами с обеих сторон, не все базовые операторы напрямую принимают растровый вход. В случаях, когда оператор ожидает геометрический вход, растр автоматически преобразуется в геометрию. Важно учитывать это при интерпретации результатов запроса.
Тип поддержки растровых данных указан для всех запросов в таблице совместимости. В настоящее время запросы, связанные с растровыми данными, доступны только для бэкенда PostGIS.
Запросы по расстоянию
Введение
Вычисление расстояний с пространственными данными сложно, потому что Земля, к сожалению, не плоская. Некоторые запросы по расстоянию с полями в географической системе координат могут потребовать другого выражения из-за ограничений PostGIS. Подробнее см. раздел Выбор SRID в документации GeoDjango Модельный API.
Запросы по расстоянию
Доступность: PostGIS, Oracle, SpatiaLite, PGRaster (Нативное)
Доступны следующие запросы по расстоянию:
Примечание
Для измерения, а не запроса расстояний, используйте функцию Distance.
Запросы по расстоянию принимают кортеж параметров, состоящий из:
- Геометрии или растра, от которого выполняются вычисления; и
- Числа или объекта
Distance, содержащего расстояние.
Если используется объект Distance, он может быть выражен в любых единицах (SQL, сгенерированный, будет использовать единицы, преобразованные в единицы поля); в противном случае числовые параметры предполагаются в единицах поля.
Примечание
В PostGIS, ST_Distance_Sphere не ограничивает типы геометрий, с которыми выполняются запросы географического расстояния. [4] Однако, эти запросы могут занимать много времени, так как расстояния по большой окружности необходимо вычислять на лету для каждой строки в запросе. Это происходит потому, что пространственный индекс на традиционных полях геометрии не может быть использован.
Для гораздо лучшей производительности при запросах расстояния на WGS84, рассмотрите использование географических столбцов в вашей базе данных вместо этого, потому что они могут использовать свой пространственный индекс в запросах расстояния. Вы можете указать GeoDjango использовать географический столбец, установив geography=True в вашем определении поля.
Например, предположим, что у нас есть модель SouthTexasCity (из тестов GeoDjango расстояния ) в проектируемой системе координат, действительной для городов южной Техаса:
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) разделены на три категории, описанные в подробности запросов растра: родная поддержка N, двусторонняя родная поддержка B, и поддержка преобразования геометрии C.
| Тип запроса | PostGIS | Oracle | MySQL [6] | SpatiaLite | PGRaster |
|---|---|---|---|---|---|
bbcontains | X | X | X | N | |
bboverlaps | X | X | X | N | |
contained | X | X | X | N | |
contains | X | X | X | X | B |
contains_properly | X | B | |||
coveredby | X | X | B | ||
covers | X | X | B | ||
crosses | X | X | C | ||
disjoint | X | X | X | X | B |
distance_gt | X | X | X | N | |
distance_gte | X | X | X | N | |
distance_lt | X | X | X | N | |
distance_lte | X | X | X | N | |
dwithin | X | X | X | B | |
equals | X | X | X | X | C |
exact | X | X | X | X | B |
intersects | X | X | X | X | B |
isvalid | X | X | X (≥ 5.7.5) | X (LWGEOM) | |
overlaps | X | X | X | X | B |
relate | X | X | X | C | |
same_as | X | X | X | X | B |
touches | X | X | X | X | B |
within | 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 |
Совместимость функций базы данных
Следующая таблица предоставляет сводку доступных функций географических баз данных для каждого пространственного бэкенда.
| Функция | PostGIS | Oracle | MySQL | SpatiaLite |
|---|---|---|---|---|
Area | X | X | X | X |
AsGeoJSON | X | X (≥ 5.7.5) | X | |
AsGML | X | X | X | |
AsKML | X | X | ||
AsSVG | X | X | ||
Azimuth | X | X (LWGEOM) | ||
BoundingCircle | X | X | ||
Centroid | X | X | X | X |
Difference | X | X | X | X |
Distance | X | X | X | X |
Envelope | X | X | X | |
ForcePolygonCW | X | X | ||
ForceRHR | X | |||
GeoHash | X | X (≥ 5.7.5) | X (LWGEOM) | |
Intersection | X | X | X | X |
IsValid | X | X | X (≥ 5.7.5) | X (LWGEOM) |
Length | X | X | X | X |
LineLocatePoint | X | X | ||
MakeValid | X | X (LWGEOM) | ||
MemSize | X | |||
NumGeometries | X | X | X | X |
NumPoints | X | X | X | X |
Perimeter | X | X | X | |
PointOnSurface | X | X | X | |
Reverse | X | X | X | |
Scale | X | X | ||
SnapToGrid | X | X | ||
SymDifference | X | X | X | X |
Transform | X | X | X | |
Translate | X | X | ||
Union | X | X | X | X |
Функции агрегирования
В следующей таблице представлен обзор доступных функций агрегирования для геопространственных бэкэндов. Обратите внимание, что MySQL не поддерживает ни одну из этих функций агрегирования и поэтому исключен из таблицы.
| Агрегат | PostGIS | Oracle | SpatiaLite |
|---|---|---|---|
Collect | X | X | |
Extent | X | X | X |
Extent3D | X | ||
MakeLine | X | X | |
Union | X | X | X |
Примечания
| [1] | См. Open Geospatial Consortium, Inc., 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] | См. Howard Butler, Martin Daly, Allan Doyle, Tim Schaub, & Christopher Schmidt, The GeoJSON Format Specification, Пересмотр 1.0 (16 июня 2008 г.). |
| [4] |
См. документацию PostGIS по ST_DistanceSphere. |
| [5] |
См. Создание пространственных индексов в руководстве MySQL: Для таблиц MyISAMSPATIAL INDEX создает индекс R-дерева. Для хранилищ данных, поддерживающих не пространственные индексы пространственных столбцов, движок создаёт индекс B-дерева. Индекс B-дерева по пространственным значениям будет полезен для поиска точных значений, но не для диапазонных сканирований. |
| [6] | См. раздел Ограничения пространственного MySQL для получения дополнительной информации. |
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.1/ref/contrib/gis/db-api/