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. Доступны пространственные запросы для растровых полей, но пространственные функции базы данных и агрегации для растровых полей не реализованы.
RasterField теперь поддерживает пространственные запросы.
Создание и сохранение моделей с геометрическими полями
Вот пример того, как создать геометрический объект (предполагая модель 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)}]},
... )
Пространственные запросы
Типы вычислений GeoDjango могут использоваться с любым методом менеджера, таким как filter(), exclude(), и т.д. Однако уникальные типы вычислений GeoDjango доступны только для пространственных полей.
Фильтры обычных полей (например, CharField) могут быть объединены с фильтрами географических полей. Географические вычисления принимают геометрические и растровые входные данные с обеих сторон, и типы ввода могут свободно смешиваться.
Общая структура географических вычислений описана ниже. Полная справка находится в справочнике по пространственным вычислениям.
Геометрические вычисления
Пространственные запросы с геометриями имеют следующий общий вид (предполагается модель Zipcode используемая в GeoDjango API модели):
>>> 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 (Native)
Доступны следующие запросы расстояния:
Примечание
Для измерения, а не запроса по расстоянию, используйте функцию 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 (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 (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 | ||
AsGML | X | X | X | |
AsKML | X | X | ||
AsSVG | X | X | ||
BoundingCircle | X | X (≥ 12.1.0.2) | ||
Centroid | X | X | X | X |
Difference | X | X | X (≥ 5.6.1) | X |
Distance | X | X | X (≥ 5.6.1) | X |
Envelope | X | X | X | |
ForceRHR | X | |||
GeoHash | X | X (LWGEOM) | ||
Intersection | X | X | X (≥ 5.6.1) | X |
IsValid | X | X | X (LWGEOM) | |
Length | X | X | 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 (≥ 5.6.1) | X |
Transform | X | X | X | |
Translate | X | X | ||
Union | X | X | X (≥ 5.6.1) | X |
Функции агрегирования
В следующей таблице приведено краткое описание доступных функций агрегирования, специфичных для геоданных, для каждого пространственного бэкенда. Обратите внимание, что MySQL не поддерживает ни одну из этих агрегатных функций и поэтому исключён из таблицы.
| Агрегация | PostGIS | Oracle | SpatiaLite |
|---|---|---|---|
Collect | X | X | |
Extent | X | X | X |
Extent3D | X | ||
MakeLine | X | X | |
Union | X | X | X |
Примечания
| [1] | См. Открытый геопространственный консорциум, Спецификация OpenGIS Simple Feature для 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, Спецификация формата GeoJSON, Редакция 1.0 (16 июня 2008 г.). |
| [4] |
См. Документация PostGIS по ST_DistanceSphere. |
| [5] |
См. Создание пространственных индексов в Руководстве по MySQL: Для таблиц MyISAM,SPATIAL INDEX создаёт индекс R-дерева. Для систем хранения, которые поддерживают не пространственные индексы пространственных столбцов, система хранения создаёт индекс B-дерева. Индекс B-дерева на пространственных значениях будет полезен для поиска точных значений, но не для диапазонных сканирований. |
| [6] | См. раздел Ограничения MySQL для пространственных данных для получения дополнительной информации. |
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/1.11/ref/contrib/gis/db-api/