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 5.6.1 пространственные расширения поддерживали только операции с ограничивающими прямоугольниками (MBR). В частности, MySQL не соответствовал стандарту OGC. Django поддерживает пространственные функции, работающие с реальными геометриями, доступными в современных версиях MySQL. Однако пространственные функции не так богаты, как в других бэкендах, таких как PostGIS.
Была добавлена поддержка пространственных функций, работающих с реальными геометриями.
Предупреждение
Истинные пространственные индексы (R-деревья) поддерживаются только для таблиц MyISAM в MySQL. [4] Другими словами, при использовании пространственных расширений 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 (Well Known Text [1]), HEXEWKB (специфичный для PostGIS — геометрия WKB в шестнадцатеричном виде [2]) и GeoJSON (см. RFC 7946). По сути, если вход не является объектом 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, MariaDB, MySQL, Oracle, SpatiaLite, PGRaster (Native)
Доступны следующие запросы по расстоянию:
distance_ltdistance_ltedistance_gtdistance_gte-
dwithin(кроме MariaDB и MySQL)
Примечание
Для измерения, а не для запросов по расстоянию, используйте функцию Distance.
Запросы по расстоянию принимают параметр в виде кортежа, состоящего из:
- Геометрии или растра для расчета расстояния; и
- Числа или объекта
Distance, содержащего расстояние.
Если используется объект Distance, он может быть выражен в любых единицах (сгенерированный SQL будет использовать единицы, преобразованные в единицы поля); в противном случае числовые параметры предполагаются в единицах поля.
Примечание
В PostGIS, ST_Distance_Sphere не ограничивает типы геометрий, с которыми выполняются запросы географических расстояний. [3] Однако эти запросы могут занимать много времени, так как расстояния по большой окружности должны вычисляться на лету для каждой строки в запросе. Это связано с тем, что пространственный индекс на традиционных полях геометрии не может использоваться.
Для значительно лучшей производительности запросов расстояний 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 | MariaDB | MySQL [5] | 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 |
isvalid | X | X | X (≥ 5.7.5) | X (LWGEOM) | ||
overlaps | X | X | X | X | X | B |
relate | 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 |
Совместимость функций базы данных
Следующая таблица содержит краткое описание доступных географически-специфичных функций базы данных для каждого пространственного бэкэнда.
| Функция | PostGIS | Oracle | MariaDB | MySQL | SpatiaLite |
|---|---|---|---|---|---|
Area | X | X | X | X | X |
AsGeoJSON | X | X (≥ 10.2.4) | 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 | X |
Difference | X | X | X | X | X |
Distance | X | X | X | X | X |
Envelope | X | X | X | X | X |
ForcePolygonCW | X | X | |||
GeoHash | X | X (≥ 5.7.5) | X (LWGEOM) | ||
Intersection | X | X | X | X | X |
IsValid | X | X | X (≥ 5.7.5) | X (LWGEOM) | |
Length | X | X | X | X | X |
LineLocatePoint | X | X | |||
MakeValid | X | X (LWGEOM) | |||
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 не поддерживает ни одну из этих функций агрегирования и поэтому исключен из таблицы.
| Агрегирование | 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 для SQL, документ 99-049 (5 мая 1999 г.), в разд. 3.2.5, стр. 3-11 (Текстовое представление геометрии в SQL). |
| [2] | См. PostGIS EWKB, EWKT и канонические формы, документация PostGIS в разд. 4.1.2. |
| [3] |
См. документацию PostGIS по ST_DistanceSphere. |
| [4] |
См. Создание пространственных индексов в Руководстве по MySQL: Для таблиц MyISAMSPATIAL INDEX создает индекс R-дерева. Для хранилищ данных, поддерживающих не пространственные индексы для пространственных столбцов, движок создает индекс B-дерева. Индекс B-дерева на пространственных значениях будет полезен для поиска точных значений, но не для диапазонного поиска. |
| [5] | См. раздел Ограничения MySQL для пространственных данных для получения дополнительной информации. |
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.0/ref/contrib/gis/db-api/