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 Spatial
Пространственные расширения 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)}]},
... )
Пространственные запросы
Типы запросов 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» в документации по выбору SRID GeoDjango API моделей.
Запросы по расстоянию
Доступность: PostGIS, MySQL, Oracle, SpatiaLite, PGRaster (родной)
Доступны следующие запросы по расстоянию:
distance_ltdistance_ltedistance_gtdistance_gte-
dwithin(кроме MySQL)
Примечание
Для измерения, а не запроса по расстояниям, используйте функцию 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 | X | B | |
covers | X | X | X | B | |
crosses | X | X | C | ||
disjoint | X | X | X | X | B |
distance_gt | X | X | X | X | N |
distance_gte | X | X | X | X | N |
distance_lt | X | X | X | X | N |
distance_lte | X | 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 | 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, Спецификацию формата GeoJSON, Редакция 1.0 (16 июня 2008 г.). |
| [4] |
См. документацию PostGIS по ST_DistanceSphere. |
| [5] |
См. Создание пространственных индексов в Справочнике MySQL: Для таблиц MyISAMSPATIAL INDEX создаёт индекс R-дерева. Для хранилищ, которые поддерживают не пространственный индексирования пространственных столбцов, движок создаёт индекс B-дерева. Индекс B-дерева на пространственных значениях будет полезен для поиска точных значений, но не для диапазонных сканирований. |
| [6] | См. раздел Ограничения MySQL Spatial для получения более подробной информации. |
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/2.2/ref/contrib/gis/db-api/