Spec-Zone.ru › Django 3.2

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

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

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 пространственных расширений

До MySQL 5.6.1 пространственные расширения поддерживали только операции с прямоугольниками минимального охвата (что MySQL называет минимальными прямоугольниками, или 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_lt
  • distance_lte
  • distance_gt
  • distance_gte
  • dwithin (кроме MariaDB и MySQL)

Примечание

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

Запросы по расстоянию принимают кортеж параметров, включающий:

  1. Геометрию или растр для расчета; и
  2. Число или объект 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 Raster (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 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 X (≥ 10.2.4) X (≥ 5.7.5) 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)
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 Specification For 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:

Для таблиц MyISAM, SPATIAL INDEX создаёт индекс R-дерева. Для хранилищ данных, поддерживающих индексирование пространственных столбцов, не связанных с пространственными данными, движок создаёт индекс B-дерева. Индекс B-дерева на пространственных значениях будет полезен для поиска точных значений, но не для диапазонных запросов.
[5] См. раздел Ограничения MySQL Spatial для получения дополнительной информации.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.2/ref/contrib/gis/db-api/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API