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 5.6.1, пространственные расширения поддерживали только операции с ограничивающими прямоугольниками (то, что MySQL называет минимальными ограничивающими прямоугольниками, или MBR). В частности, MySQL не соответствовал стандарту OGC. Django поддерживает пространственные функции, работающие с реальными геометриями, доступными в современных версиях MySQL. Однако пространственные функции не так богаты, как в других бэкендах, таких как PostGIS.
Поддержка растровых данных
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 (см. 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 на растровый объект, или и то, и другое. Для указания индекса полосы растрового входного параметра справа можно передать в поиск тройку, как показано ниже:
>>> qs = SouthTexasCity.objects.filter(point__distance_gte=(rst, 2, D(km=7)))
Где для поиска будет использоваться полоса с индексом 2 (третья полоса) растра rst.
Таблицы совместимости
Пространственные запросы
В следующей таблице представлен обзор доступных пространственных запросов для каждого бэкенда пространственной базы данных. Запросы PostGIS Raster (PGRaster) разделены на три категории, описанные в подробности поиска растров: родная поддержка N, двусторонняя родная поддержка B, и поддержка преобразования геометрии C.
| Тип поиска | PostGIS | Oracle | MariaDB | MySQL [4] | 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 | ||
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 | 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/RTTOPO) | |||
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/RTTOPO) | ||
Intersection | X | X | X | X | X |
IsValid | X | X | X (≥ 5.7.5) | X | |
Length | X | X | X | X | X |
LineLocatePoint | X | X | |||
MakeValid | X | X (LWGEOM/RTTOPO) | |||
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] | См. Открытый геопространственный консорциум, Спецификация OpenGIS Simple Feature 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 пространственных данных для получения более подробной информации. |
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.1/ref/contrib/gis/db-api/