Spec-Zone.ru › Django 6.0

Руководство по GeoDjango

Введение

GeoDjango — это встроенный модуль contrib для Django, который превращает его в первоклассный географический веб-фреймворк. GeoDjango стремится максимально упростить создание географических веб-приложений, например служб, основанных на местоположении. Его возможности включают:

  • Поля моделей Django для геометрий OGC и растровых данных.
  • Расширения ORM Django для запросов и манипулирования пространственными данными.
  • Слабо связанные высокоуровневые интерфейсы Python для операций с геометрией и растрами в ГИС, а также для обработки данных в различных форматах.
  • Редактирование геометрических полей в административном интерфейсе.

Это руководство предполагает знакомство с Django; поэтому, если вы только начинаете работать с Django, сначала ознакомьтесь с обычным руководством, чтобы познакомиться с Django.

Примечание

Для GeoDjango требуются дополнительные компоненты помимо тех, которые нужны Django, — подробнее см. в документации по установке.

В этом руководстве вы создадите географическое веб-приложение для просмотра границ стран мира. [1] Часть кода, использованного в этом руководстве, взята из проекта базовых приложений GeoDjango и/или вдохновлена им. [2]

Примечание

Для получения пошаговых инструкций проходите разделы руководства последовательно.

Настройка

Создание пространственной базы данных

Как правило, специальная настройка не требуется, поэтому базу данных можно создать так же, как и для любого другого проекта. Ниже приведены рекомендации для некоторых баз данных:

  • Установка PostGIS
  • Установка SpatiaLite

Создание нового проекта

Используйте стандартный скрипт django-admin, чтобы создать проект с именем geodjango:

$ django-admin startproject geodjango
...\> django-admin startproject geodjango

Будет создан новый проект. Теперь создайте приложение Django world в проекте geodjango:

$ cd geodjango
$ python manage.py startapp world
...\> cd geodjango
...\> py manage.py startapp world

Настройка settings.py

Настройки проекта geodjango хранятся в файле geodjango/settings.py. Измените настройки подключения к базе данных в соответствии со своей конфигурацией:

DATABASES = {
    "default": {
        "ENGINE": "django.contrib.gis.db.backends.postgis",
        "NAME": "geodjango",
        "USER": "geo",
    },
}

Кроме того, измените параметр INSTALLED_APPS, включив в него django.contrib.admin, django.contrib.gis и world (созданное вами приложение):

INSTALLED_APPS = [
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",
    "django.contrib.gis",
    "world",
]

Географические данные

Границы стран мира

Данные о границах стран мира доступны в этом ZIP-файле. Создайте каталог data в приложении world, скачайте данные о границах стран мира и распакуйте архив. В GNU/Linux используйте следующие команды:

$ mkdir world/data
$ cd world/data
$ wget https://web.archive.org/web/20231220150759/https://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip
$ unzip TM_WORLD_BORDERS-0.3.zip
$ cd ../..
...\> mkdir world\data
...\> cd world\data
...\> wget https://web.archive.org/web/20231220150759/https://thematicmapping.org/downloads/TM_WORLD_BORDERS-0.3.zip
...\> unzip TM_WORLD_BORDERS-0.3.zip
...\> cd ..\..

ZIP-файл с данными о границах стран мира содержит набор файлов данных, вместе известных как шейп-файл ESRI, один из наиболее популярных форматов геопространственных данных. После распаковки набор данных о границах стран мира включает файлы со следующими расширениями:

  • .shp: содержит векторные данные геометрии границ стран мира.
  • .shx: файл пространственного индекса для геометрий, хранящихся в .shp.
  • .dbf: файл базы данных для хранения негeометрических атрибутов (например, целочисленных и символьных полей).
  • .prj: содержит сведения о пространственной системе координат географических данных, хранящихся в шейп-файле.

Изучение пространственных данных с помощью ogrinfo

Утилита GDAL ogrinfo позволяет изучать метаданные шейп-файлов и других источников векторных данных:

$ ogrinfo world/data/TM_WORLD_BORDERS-0.3.shp
INFO: Open of `world/data/TM_WORLD_BORDERS-0.3.shp'
      using driver `ESRI Shapefile' successful.
1: TM_WORLD_BORDERS-0.3 (Polygon)
...\> ogrinfo world\data\TM_WORLD_BORDERS-0.3.shp
INFO: Open of `world/data/TM_WORLD_BORDERS-0.3.shp'
      using driver `ESRI Shapefile' successful.
1: TM_WORLD_BORDERS-0.3 (Polygon)

ogrinfo сообщает, что в шейп-файле один слой и что этот слой содержит данные полигонов. Чтобы узнать больше, укажем имя слоя и воспользуемся параметром -so, чтобы получить только важную сводную информацию:

$ ogrinfo -so world/data/TM_WORLD_BORDERS-0.3.shp TM_WORLD_BORDERS-0.3
INFO: Open of `world/data/TM_WORLD_BORDERS-0.3.shp'
      using driver `ESRI Shapefile' successful.

Layer name: TM_WORLD_BORDERS-0.3
Metadata:
  DBF_DATE_LAST_UPDATE=2008-07-30
Geometry: Polygon
Feature Count: 246
Extent: (-180.000000, -90.000000) - (180.000000, 83.623596)
Layer SRS WKT:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["latitude",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["longitude",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    ID["EPSG",4326]]
Data axis to CRS axis mapping: 2,1
FIPS: String (2.0)
ISO2: String (2.0)
ISO3: String (3.0)
UN: Integer (3.0)
NAME: String (50.0)
AREA: Integer (7.0)
POP2005: Integer64 (10.0)
REGION: Integer (3.0)
SUBREGION: Integer (3.0)
LON: Real (8.3)
LAT: Real (7.3)
...\> ogrinfo -so world\data\TM_WORLD_BORDERS-0.3.shp TM_WORLD_BORDERS-0.3
INFO: Open of `world/data/TM_WORLD_BORDERS-0.3.shp'
      using driver `ESRI Shapefile' successful.

Layer name: TM_WORLD_BORDERS-0.3
Metadata:
  DBF_DATE_LAST_UPDATE=2008-07-30
Geometry: Polygon
Feature Count: 246
Extent: (-180.000000, -90.000000) - (180.000000, 83.623596)
Layer SRS WKT:
GEOGCRS["WGS 84",
    DATUM["World Geodetic System 1984",
        ELLIPSOID["WGS 84",6378137,298.257223563,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["latitude",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["longitude",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    ID["EPSG",4326]]
Data axis to CRS axis mapping: 2,1
FIPS: String (2.0)
ISO2: String (2.0)
ISO3: String (3.0)
UN: Integer (3.0)
NAME: String (50.0)
AREA: Integer (7.0)
POP2005: Integer64 (10.0)
REGION: Integer (3.0)
SUBREGION: Integer (3.0)
LON: Real (8.3)
LAT: Real (7.3)

Подробная сводка сообщает количество объектов в слое (246), географические границы данных, пространственную систему координат («SRS WKT»), а также тип каждого поля атрибутов. Например, FIPS: String (2.0) указывает, что символьное поле FIPS имеет максимальную длину 2. Аналогично, LON: Real (8.3) — это поле с плавающей точкой, вмещающее не более 8 цифр, до трёх из которых находятся после десятичной точки.

Географические модели

Определение географической модели

Теперь, когда вы изучили набор данных с помощью ogrinfo, создайте модель GeoDjango для представления этих данных:

from django.contrib.gis.db import models


class WorldBorder(models.Model):
    # Regular Django fields corresponding to the attributes in the
    # world borders shapefile.
    name = models.CharField(max_length=50)
    area = models.IntegerField()
    pop2005 = models.IntegerField("Population 2005")
    fips = models.CharField("FIPS Code", max_length=2, null=True)
    iso2 = models.CharField("2 Digit ISO", max_length=2)
    iso3 = models.CharField("3 Digit ISO", max_length=3)
    un = models.IntegerField("United Nations Code")
    region = models.IntegerField("Region Code")
    subregion = models.IntegerField("Sub-Region Code")
    lon = models.FloatField()
    lat = models.FloatField()

    # GeoDjango-specific: a geometry field (MultiPolygonField)
    mpoly = models.MultiPolygonField()

    # Returns the string representation of the model.
    def __str__(self):
        return self.name

Обратите внимание, что модуль models импортирован из django.contrib.gis.db.

По умолчанию для геометрических полей используется пространственная система координат WGS84 (то есть SRID равен 4326). Другими словами, координаты поля задаются парами долгота и широта в градусах. Чтобы использовать другую систему координат, задайте SRID геометрического поля с помощью аргумента srid. Используйте целое число, соответствующее коду EPSG системы координат.

Выполнение migrate

После определения модели необходимо синхронизировать её с базой данных. Сначала создайте миграцию базы данных:

$ python manage.py makemigrations
Migrations for 'world':
  world/migrations/0001_initial.py:
    + Create model WorldBorder
...\> py manage.py makemigrations
Migrations for 'world':
  world/migrations/0001_initial.py:
    + Create model WorldBorder

Посмотрим на SQL-код, который создаст таблицу для модели WorldBorder:

$ python manage.py sqlmigrate world 0001
...\> py manage.py sqlmigrate world 0001

Эта команда должна вывести следующий результат:

BEGIN;
--
-- Create model WorldBorder
--
CREATE TABLE "world_worldborder" (
    "id" bigint NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY,
    "name" varchar(50) NOT NULL,
    "area" integer NOT NULL,
    "pop2005" integer NOT NULL,
    "fips" varchar(2) NOT NULL,
    "iso2" varchar(2) NOT NULL,
    "iso3" varchar(3) NOT NULL,
    "un" integer NOT NULL,
    "region" integer NOT NULL,
    "subregion" integer NOT NULL,
    "lon" double precision NOT NULL,
    "lat" double precision NOT NULL
    "mpoly" geometry(MULTIPOLYGON,4326) NOT NULL
)
;
CREATE INDEX "world_worldborder_mpoly_id" ON "world_worldborder" USING GIST ("mpoly");
COMMIT;

Если всё выглядит правильно, выполните migrate, чтобы создать таблицу в базе данных:

$ python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, world
Running migrations:
  ...
  Applying world.0001_initial... OK
...\> py manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions, world
Running migrations:
  ...
  Applying world.0001_initial... OK

Импорт пространственных данных

В этом разделе показано, как импортировать шейп-файл с границами стран мира в базу данных с помощью моделей GeoDjango и утилиты импорта данных LayerMapping.

Существует множество способов импортировать данные в пространственную базу данных. Помимо инструментов, включённых в GeoDjango, можно использовать следующие:

  • ogr2ogr: утилита командной строки, входящая в состав GDAL и позволяющая импортировать данные во многих векторных форматах в базы данных PostGIS, MySQL и Oracle.
  • shp2pgsql: эта утилита, входящая в состав PostGIS, импортирует шейп-файлы ESRI в PostGIS.

Интерфейс GDAL

Ранее вы использовали ogrinfo для изучения содержимого шейп-файла с границами стран мира. GeoDjango также включает интерфейс Python к мощной библиотеке OGR из GDAL, который может работать со всеми источниками векторных данных, поддерживаемыми OGR.

Сначала запустите оболочку Django:

$ python manage.py shell
...\> py manage.py shell

Если ранее в этом руководстве вы скачали данные «Границы стран мира», путь к ним можно определить с помощью класса Python pathlib.Path:

>>> from pathlib import Path
>>> import world
>>> world_shp = Path(world.__file__).resolve().parent / "data" / "TM_WORLD_BORDERS-0.3.shp"

Теперь откройте шейп-файл с границами стран мира с помощью интерфейса DataSource GeoDjango:

>>> from django.contrib.gis.gdal import DataSource
>>> ds = DataSource(world_shp)
>>> print(ds)
/ ... /geodjango/world/data/TM_WORLD_BORDERS-0.3.shp (ESRI Shapefile)

Объекты источников данных могут содержать несколько слоёв геопространственных объектов; однако шейп-файлы могут содержать только один слой:

>>> print(len(ds))
1
>>> lyr = ds[0]
>>> print(lyr)
TM_WORLD_BORDERS-0.3

Можно узнать тип геометрии слоя и количество содержащихся в нём объектов:

>>> print(lyr.geom_type)
Polygon
>>> print(len(lyr))
246

Примечание

К сожалению, формат шейп-файлов не позволяет указывать типы геометрии более точно. Этот шейп-файл, как и многие другие, на самом деле содержит геометрии MultiPolygon, а не полигоны. В моделях важно использовать более общий тип поля: поле GeoDjango MultiPolygonField принимает геометрию Polygon, а поле PolygonField не принимает геометрию типа MultiPolygon. Поэтому в определённой выше модели WorldBorder используется MultiPolygonField.

У объекта Layer также может быть связана пространственная система координат. Если она есть, атрибут srs вернёт объект SpatialReference:

>>> srs = lyr.srs
>>> print(srs)
GEOGCS["WGS 84",
DATUM["WGS_1984",
    SPHEROID["WGS 84",6378137,298.257223563,
        AUTHORITY["EPSG","7030"]],
    AUTHORITY["EPSG","6326"]],
PRIMEM["Greenwich",0,
    AUTHORITY["EPSG","8901"]],
UNIT["degree",0.0174532925199433,
    AUTHORITY["EPSG","9122"]],
AXIS["Latitude",NORTH],
AXIS["Longitude",EAST],
AUTHORITY["EPSG","4326"]]
>>> srs.proj  # PROJ representation
'+proj=longlat +datum=WGS84 +no_defs'

Этот шейп-файл использует популярную пространственную систему координат WGS84 — другими словами, данные представлены парами долгота и широта в градусах.

Кроме того, шейп-файлы поддерживают поля атрибутов, которые могут содержать дополнительные данные. Вот поля слоя «Границы стран мира»:

>>> print(lyr.fields)
['FIPS', 'ISO2', 'ISO3', 'UN', 'NAME', 'AREA', 'POP2005', 'REGION', 'SUBREGION', 'LON', 'LAT']

Следующий код позволяет изучить типы OGR (например, целое число или строка), связанные с каждым из полей:

>>> [fld.__name__ for fld in lyr.field_types]
['OFTString', 'OFTString', 'OFTString', 'OFTInteger', 'OFTString', 'OFTInteger', 'OFTInteger64', 'OFTInteger', 'OFTInteger', 'OFTReal', 'OFTReal']

Можно перебирать все объекты слоя и извлекать информацию как из геометрии объекта (доступной через атрибут geom), так и из полей атрибутов объекта (их значения доступны через метод get()):

>>> for feat in lyr:
...     print(feat.get("NAME"), feat.geom.num_points)
...
Guernsey 18
Jersey 26
South Georgia South Sandwich Islands 338
Taiwan 363

Объекты Layer можно срезать:

>>> lyr[0:2]
[<django.contrib.gis.gdal.feature.Feature object at 0x2f47690>, <django.contrib.gis.gdal.feature.Feature object at 0x2f47650>]

Отдельные объекты можно получить по их идентификатору:

>>> feat = lyr[234]
>>> print(feat.get("NAME"))
San Marino

Геометрию границ можно экспортировать в форматах WKT и GeoJSON:

>>> geom = feat.geom
>>> print(geom.wkt)
POLYGON ((12.415798 43.957954,12.450554 ...
>>> print(geom.json)
{ "type": "Polygon", "coordinates": [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...

LayerMapping

Для импорта данных используйте LayerMapping в скрипте Python. Создайте файл load.py в приложении world со следующим кодом:

from pathlib import Path
from django.contrib.gis.utils import LayerMapping
from .models import WorldBorder

world_mapping = {
    "fips": "FIPS",
    "iso2": "ISO2",
    "iso3": "ISO3",
    "un": "UN",
    "name": "NAME",
    "area": "AREA",
    "pop2005": "POP2005",
    "region": "REGION",
    "subregion": "SUBREGION",
    "lon": "LON",
    "lat": "LAT",
    "mpoly": "MULTIPOLYGON",
}

world_shp = Path(__file__).resolve().parent / "data" / "TM_WORLD_BORDERS-0.3.shp"


def run(verbose=True):
    lm = LayerMapping(WorldBorder, world_shp, world_mapping, transform=False)
    lm.save(strict=True, verbose=verbose)

Несколько пояснений к происходящему:

  • Каждый ключ в словаре world_mapping соответствует полю модели WorldBorder. Значение — это имя поля шейп-файла, из которого будут загружены данные.
  • Ключ mpoly для геометрического поля имеет значение MULTIPOLYGON — это тип геометрии, в который GeoDjango импортирует поле. Даже простые полигоны в шейп-файле автоматически преобразуются в коллекции перед вставкой в базу данных.
  • Путь к шейп-файлу не абсолютный — другими словами, если переместить приложение world (вместе с подкаталогом data) в другое место, скрипт всё равно будет работать.
  • Аргумент transform имеет значение False, потому что данные в шейп-файле не нужно преобразовывать — они уже представлены в WGS84 (SRID=4326).

Затем запустите оболочку Django из каталога проекта geodjango:

$ python manage.py shell
...\> py manage.py shell

Затем импортируйте модуль load, вызовите функцию run и наблюдайте, как LayerMapping выполняет свою работу:

>>> from world import load
>>> load.run()

Попробуйте ogrinspect

Теперь, когда вы знаете, как определять географические модели и импортировать данные с помощью утилиты импорта данных LayerMapping, этот процесс можно дополнительно автоматизировать с помощью команды управления ogrinspect. Команда ogrinspect анализирует источник векторных данных, поддерживаемый GDAL (например, шейп-файл), и автоматически создаёт определение модели и словарь LayerMapping.

Общий формат команды выглядит так:

$ python manage.py ogrinspect [options] <data_source> <model_name> [options]
...\> py manage.py ogrinspect [options] <data_source> <model_name> [options]

data_source — это путь к источнику данных, поддерживаемому GDAL, а model_name — имя модели. Чтобы дополнительно настроить создание модели, можно использовать параметры командной строки.

Например, следующая команда почти автоматически воссоздаёт модель WorldBorder и словарь сопоставления, созданные выше:

$ python manage.py ogrinspect world/data/TM_WORLD_BORDERS-0.3.shp WorldBorder \
    --srid=4326 --mapping --multi
...\> py manage.py ogrinspect world\data\TM_WORLD_BORDERS-0.3.shp WorldBorder \
    --srid=4326 --mapping --multi

Несколько пояснений к указанным выше параметрам командной строки:

  • Параметр --srid=4326 задаёт SRID для географического поля.
  • Параметр --mapping указывает ogrinspect также создать словарь сопоставления для использования с LayerMapping.
  • Параметр --multi указан, чтобы географическое поле было типа MultiPolygonField, а не просто типа PolygonField.

Команда выдаёт следующий результат, который можно напрямую скопировать в файл models.py приложения GeoDjango:

# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models


class WorldBorder(models.Model):
    fips = models.CharField(max_length=2)
    iso2 = models.CharField(max_length=2)
    iso3 = models.CharField(max_length=3)
    un = models.IntegerField()
    name = models.CharField(max_length=50)
    area = models.IntegerField()
    pop2005 = models.IntegerField()
    region = models.IntegerField()
    subregion = models.IntegerField()
    lon = models.FloatField()
    lat = models.FloatField()
    geom = models.MultiPolygonField(srid=4326)


# Auto-generated `LayerMapping` dictionary for WorldBorder model
worldborders_mapping = {
    "fips": "FIPS",
    "iso2": "ISO2",
    "iso3": "ISO3",
    "un": "UN",
    "name": "NAME",
    "area": "AREA",
    "pop2005": "POP2005",
    "region": "REGION",
    "subregion": "SUBREGION",
    "lon": "LON",
    "lat": "LAT",
    "geom": "MULTIPOLYGON",
}

Пространственные запросы

Пространственные запросы

GeoDjango добавляет пространственные поисковые запросы в ORM Django. Например, можно найти страну в таблице WorldBorder, в которой находится заданная точка. Сначала запустите оболочку управления:

$ python manage.py shell
...\> py manage.py shell

Теперь задайте интересующую точку [3]:

>>> pnt_wkt = "POINT(-95.3385 29.7245)"

Строка pnt_wkt представляет точку с долготой −95,3385 градуса и широтой 29,7245 градуса. Геометрия задана в формате, известном как Well Known Text (WKT), — стандарте, разработанном Open Geospatial Consortium (OGC). [4] Импортируйте модель WorldBorder и выполните поиск contains, передав в качестве параметра pnt_wkt:

>>> from world.models import WorldBorder
>>> WorldBorder.objects.filter(mpoly__contains=pnt_wkt)
<QuerySet [<WorldBorder: United States>]>

В результате получена модель QuerySet, содержащая только один объект: границу США (именно этого и следовало ожидать).

Аналогичным образом можно использовать объект геометрии GEOS. Здесь можно объединить пространственный поиск intersects с методом get, чтобы получить только экземпляр WorldBorder для Сан-Марино, а не набор запросов:

>>> from django.contrib.gis.geos import Point
>>> pnt = Point(12.4604, 43.9420)
>>> WorldBorder.objects.get(mpoly__intersects=pnt)
<WorldBorder: San Marino>

Поиски contains и intersects — лишь часть доступных запросов; дополнительную информацию см. в документации API базы данных GeoDjango.

Автоматические пространственные преобразования

При выполнении пространственных запросов GeoDjango автоматически преобразует геометрии, если они заданы в другой системе координат. В следующем примере координаты будут указаны в EPSG SRID 32140 — системе координат, предназначенной только для южного Техаса, в метрах, а не в градусах:

>>> from django.contrib.gis.geos import GEOSGeometry, Point
>>> pnt = Point(954158.1, 4215137.1, srid=32140)

Обратите внимание, что pnt можно также создать с помощью EWKT — «расширенной» формы WKT, включающей SRID:

>>> pnt = GEOSGeometry("SRID=32140;POINT(954158.1 4215137.1)")

ORM GeoDjango автоматически оборачивает значения геометрии в SQL-преобразование, позволяя разработчику работать на более высоком уровне абстракции:

>>> qs = WorldBorder.objects.filter(mpoly__intersects=pnt)
>>> print(qs.query)  # Generating the SQL
SELECT "world_worldborder"."id", "world_worldborder"."name", "world_worldborder"."area",
"world_worldborder"."pop2005", "world_worldborder"."fips", "world_worldborder"."iso2",
"world_worldborder"."iso3", "world_worldborder"."un", "world_worldborder"."region",
"world_worldborder"."subregion", "world_worldborder"."lon", "world_worldborder"."lat",
"world_worldborder"."mpoly" FROM "world_worldborder"
WHERE ST_Intersects("world_worldborder"."mpoly", ST_Transform(%s, 4326))
>>> qs  # printing evaluates the queryset
<QuerySet [<WorldBorder: United States>]>

Прямые запросы

При использовании прямых запросов необходимо оборачивать геометрические поля, чтобы GEOS мог распознать значение поля:

>>> from django.db import connection
>>> # or if you're querying a non-default database:
>>> from django.db import connections
>>> connection = connections["your_gis_db_alias"]
>>> City.objects.raw(
...     "SELECT id, name, %s as point from myapp_city" % (connection.ops.select % "point")
... )

Используйте прямые запросы, только если точно знаете, что делаете.

Геометрии с отложенной загрузкой

GeoDjango загружает геометрии в стандартизованном текстовом представлении. При первом обращении к геометрическому полю GeoDjango создаёт объект GEOSGeometry, предоставляющий мощные возможности, например свойства сериализации для популярных геопространственных форматов:

>>> sm = WorldBorder.objects.get(name="San Marino")
>>> sm.mpoly
<MultiPolygon object at 0x24c6798>
>>> sm.mpoly.wkt  # WKT
MULTIPOLYGON (((12.4157980000000006 43.9579540000000009, 12.4505540000000003 43.9797209999999978, ...
>>> sm.mpoly.wkb  # WKB (as Python binary buffer)
<read-only buffer for 0x1fe2c70, size -1, offset 0 at 0x2564c40>
>>> sm.mpoly.geojson  # GeoJSON
'{ "type": "MultiPolygon", "coordinates": [ [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], ...

Это также даёт доступ ко всем расширенным геометрическим операциям, предоставляемым библиотекой GEOS:

>>> pnt = Point(12.4604, 43.9420)
>>> sm.mpoly.contains(pnt)
True
>>> pnt.contains(sm.mpoly)
False

Географические аннотации

GeoDjango также предоставляет набор географических аннотаций для вычисления расстояний и выполнения ряда других операций (пересечение, разность и т. д.). См. документацию «Географические функции базы данных».

Отображение данных на карте

Географический административный интерфейс

Административное приложение Django поддерживает редактирование геометрических полей.

Основы

Административный интерфейс Django позволяет пользователям создавать и изменять геометрии на интерактивной карте JavaScript (на базе OpenLayers).

Начнём сразу. Создайте файл admin.py в приложении world со следующим кодом:

from django.contrib.gis import admin
from .models import WorldBorder

admin.site.register(WorldBorder, admin.ModelAdmin)

Затем измените файл urls.py в каталоге приложения geodjango следующим образом:

from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
]

Создайте пользователя-администратора:

$ python manage.py createsuperuser
...\> py manage.py createsuperuser

Затем запустите сервер разработки Django:

$ python manage.py runserver
...\> py manage.py runserver

Наконец, откройте http://localhost:8000/admin/ и войдите под созданным пользователем. Перейдите к любой записи WorldBorder — границы можно редактировать, щёлкая по полигону и перетаскивая вершины в нужное положение.

GISModelAdmin

При использовании GISModelAdmin GeoDjango отображает в административном интерфейсе слой OpenStreetMap. Он даёт больше контекста (в том числе сведения об улицах и дорогах), чем доступно при использовании ModelAdmin, использующего набор данных WMS Vector Map Level 0, размещённый на OSGeo.

Необходимо установить файлы преобразования датумов PROJ (подробнее см. инструкции по установке PROJ).

Если это требование выполнено, используйте класс параметров GISModelAdmin в файле admin.py:

admin.site.register(WorldBorder, admin.GISModelAdmin)

Сноски

[1]

Особая благодарность Bjørn Sandvik из mastermaps.net за предоставление и поддержку этого набора данных.

[2]

Базовые приложения GeoDjango написали Dane Springmeyer, Josh Livni и Christopher Schmidt.

[3]

Эта точка соответствует Юридическому центру Хьюстонского университета.

[4]

Open Geospatial Consortium, Inc., спецификация OpenGIS Simple Feature для SQL.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/ref/contrib/gis/tutorial/

Spec-Zone.ru

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