7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

GeoDjangoを触ってみよう!

Last updated at Posted at 2021-12-01

はじめに

この記事はMIERUNE Advent Calendar 2021 2日目の記事です。今回はGISに絡んだ記事を書いてみたいと思っていたので、GeoDjangoを触ってみよう!というテーマで執筆させていただきました。

GeoDjangoとは

Djangoが持つモジュールで、利用することでDjangoを通して地理空間データを扱うことができるようになります。Djangoそのものに含まれているモジュールです(ソースコード)。

Django公式ドキュメントのトップページでも紹介されており、そこでは以下のように記載されています。

GeoDjango は世界規模の地理情報 Web フレームワークを目指しています。 GeoDjango の目的は、地理情報システム (GIS) のWeb アプリケーションの開発をより簡単にし、空間データ (spatially enabled data) を活用することにあります。

GeoDjangoではGDAL APIをサポートしており、Djangoを介して一部のGDALの機能を利用することができます。

前提

この記事では、Django公式ドキュメントのGeoDjangoチュートリアルに則って、内容をかいつまんで進めてみます。

対象

  • Djangoはある程度触ったことがある
  • GeoDjangoははじめて

バージョン

python_version = "3.8"
django = "==3.2.6"
psycopg2-binary = "==2.9.1"

ソースコード/ 環境

以下に実行したソースコードを載せておきます。
https://github.com/selfsryo/GeoDjangoOfficialTutorial

GeoDjangoを扱うには当然Djangoのインストールと、地理空間用のDB(PostGIS等)が必要になります。今回はDockerでDjango + PostGISの環境を構築しました。GDALなどのGISに必要なライブラリもインストールしています。

以下のような構成になっています。

GeoDjangoOfficialTutorial
├── .gitignore
├── docker-compose.yml
├── geodjango
│   ├── .env.sample
│   ├── Dockerfile
│   ├── Pipfile
│   ├── entrypoint.sh
│   ├── geodjango
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── manage.py
│   └── world
│       ├── __init__.py
│       ├── admin.py
│       ├── apps.py
│       ├── data
│       │   ├── Readme.txt
│       │   ├── TM_WORLD_BORDERS-0.3.dbf
│       │   ├── TM_WORLD_BORDERS-0.3.prj
│       │   ├── TM_WORLD_BORDERS-0.3.shp
│       │   └──  TM_WORLD_BORDERS-0.3.shx
│       ├── load.py
│       ├── migrations
│       │   ├── 0001_initial.py
│       │   └── __init__.py
│       ├── models.py
│       ├── tests.py
│       └── views.py
└── postgres
    ├── .env.db.sample
    ├── Dockerfile
    └── sql
        └── init.sql

やってみよう

準備

まずはgeodjangoというDjangoのプロジェクトを作成します。Dockerを使っている場合はコンテナの中に入るなりして実行します。

$ django-admin startproject geodjango

その後、worldというDjangoのアプリケーションを作成します。

$ cd geodjango
$ python3 manage.py startapp world

settings.pyINSTALLED_APP'django.contrib.gis'と、先ほど作成したworldを追加します。なお、自分の場合はDockerを使っているので、いくつかの値を環境変数としてgeodjango/.envから読み込むようにしています。DATABASESの設定値もDockerのPostGISに接続するようにしています。以上を踏まえ、settings.pyは以下のようになりました。

import os
from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent.parent

# 修正
SECRET_KEY = os.environ.get("SECRET_KEY")

# 修正
DEBUG = int(os.environ.get("DEBUG", default=0))

ALLOWED_HOSTS = []


INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # 追加
    'django.contrib.gis',
    'world',
]

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'geodjango.urls'

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

WSGI_APPLICATION = 'geodjango.wsgi.application'

# 修正
DATABASES = {
    'default': {
        'ENGINE': os.environ.get('DATABASE_ENGINE', 'django.contrib.gis.db.backends.postgis'),
        'NAME': os.environ.get('DATABASE_DB', 'postgres'),
        'USER': os.environ.get('DATABASE_USER', 'postgres'),
        'PASSWORD': os.environ.get('DATABASE_PASSWORD', 'password1234'),
        'HOST': os.environ.get('DATABASE_HOST', 'postgres'),
        'PORT': os.environ.get('DATABASE_PORT', '5432'),
    }
}


AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

# 修正
LANGUAGE_CODE = 'ja'

# 修正
TIME_ZONE = 'Asia/Tokyo'

USE_I18N = True

USE_L10N = True

USE_TZ = True

STATIC_URL = '/static/'

DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'

その後今回使用する国境データを用意します。データはこちら(クリックするとzipがダウンロードされます)から入手することができます。先ほど作成したアプリケーションのworldの中にdataというフォルダを作り、その中で落としたzipを解凍します。中にはSharpefileが入っています(各ファイルの説明はこちら参照)。解凍後、zipは削除してしまいましょう。ファイルの階層は以下のようになります。

world
├── data
│   ├── Readme.txt
│   ├── TM_WORLD_BORDERS-0.3.dbf
│   ├── TM_WORLD_BORDERS-0.3.prj
│   ├── TM_WORLD_BORDERS-0.3.shp
│   └── TM_WORLD_BORDERS-0.3.shx
│
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│   └── __init__.py
├── models.py
├── tests.py
└── views.py

ogrinfo

ここで、ogrinfoで国境データのShapefileの情報を覗いてみます。先ほど紹介したリポジトリからDockerを利用していると、コンテナの中で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)

TM_WORLD_BORDERS-0.3というレイヤを持っていることがわかるので、詳細を出力してみます。レイヤ名を指定して-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)

これで、レイヤ内の地物数(246)、空間参照系、および属性のタイプ等が確認できます。

モデルの定義

上の属性に合わせて、models.pyを以下のように定義します。modelsはdjango.db.modelsではなく、django.contrib.gis.db.modelsからimportします。

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

mpoly(MultiPolygonField)には何も指定していませんが、空間参照系はデフォルトでsrid=4326となっています(参照)。他の空間参照系を指定したい場合は引数にsridで指定します。

models.pyを定義したら、以下のコマンドでマイグレーションを実行します。

$ python3 manage.py makemigrations
$ python3 manage.py migrate

インポート実行

先ほどダウンロードした国境データのShapefileをDBにインポートする方法はいくつかありますが、今回はGeoDjangoに備わっているLayerMappingを利用してみます(こちら参照)。

後ほどスクリプトで実行しますが、いったんDjango Shellを用いつつ手順を追っていきます。

$ python3 manage.py shell

先ほどダウンロードした国境データのShapefileをPythonのPathオブジェクトにします。

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

続いて、django.contrib.gis.gdal.DataSourceこちら)を利用して、国境データのShapefileを開きます。

>>> from django.contrib.gis.gdal import DataSource
>>> ds = DataSource(world_shp)
>>> ds
<django.contrib.gis.gdal.datasource.DataSource object at 0x7f0a6df717c0>
>>> print(ds)
/usr/src/app/world/data/TM_WORLD_BORDERS-0.3.shp (ESRI Shapefile)

レイヤを開いてみます。Shapefileは1つのレイヤしか持てませんが、確認してみると先ほどogrinfoで確認できたTM_WORLD_BORDERS-0.3が表示されます。以下のlyrLayerオブジェクト(こちら)です。

>>> print(len(ds))
>>> lyr = ds[0]
>>> lyr
<django.contrib.gis.gdal.layer.Layer object at 0x7f0a6df71700>
>>> print(lyr)
TM_WORLD_BORDERS-0.3

レイヤからジオメトリタイプや地物数、属性フィールドも確認できます。

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

このLayerオブジェクトに空間参照系が関連づいていた場合、srsという属性を持ちます。これはSpatialRegerenceというオブジェクト(こちら)として定義されています。またproj属性を確認することで、測地系がWGS84だと判別できます。

>>> srs = lyr.srs
>>> srs
<django.contrib.gis.gdal.srs.SpatialReference object at 0x7f9b6bd8c670>
>>> 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=longlat +datum=WGS84 +no_defs'

レイヤから任意の地物を取得してみます。これはFeatureオブジェクト(こちら)として取得することができます。

>>> feat = lyr[234]
>>> feat
<django.contrib.gis.gdal.feature.Feature object at 0x7f9b6bd14970>
>>> print(feat.get('NAME'))
San Marino

Featureからはジオメトリを取得でき、WKTおよびGeoJSONとして出力することが可能です。

>>> geom = feat.geom
>>> print(geom.wkt)
POLYGON ((12.415798 43.957954,12.450554 43.979721,12.453888 43.981667,12.4625 43.984718,12.471666 43.986938,12.492777 43.989166,12.505554 43.988609,12.509998 43.986938,12.510277 43.982773,12.511665 43.943329,12.510555 43.939163,12.496387 43.923332,12.494999 43.914719,12.487778 43.90583,12.474443 43.897217,12.464722 43.895554,12.459166 43.896111,12.416388 43.904716,12.412222 43.906105,12.407822 43.913658,12.403889 43.926666,12.404999 43.948326,12.408888 43.954994,12.415798 43.957954))
>>> print(geom.json)
{ "type": "Polygon", "coordinates": [ [ [ 12.415798, 43.957954 ], [ 12.450554, 43.979721 ], [ 12.453888, 43.981667 ], [ 12.4625, 43.984718 ], [ 12.471666, 43.986938 ], [ 12.492777, 43.989166 ], [ 12.505554, 43.988609 ], [ 12.509998, 43.986938 ], [ 12.510277, 43.982773 ], [ 12.511665, 43.943329 ], [ 12.510555, 43.939163 ], [ 12.496387, 43.923332 ], [ 12.494999, 43.914719 ], [ 12.487778, 43.90583 ], [ 12.474443, 43.897217 ], [ 12.464722, 43.895554 ], [ 12.459166, 43.896111 ], [ 12.416388, 43.904716 ], [ 12.412222, 43.906105 ], [ 12.407822, 43.913658 ], [ 12.403889, 43.926666 ], [ 12.404999, 43.948326 ], [ 12.408888, 43.954994 ], [ 12.415798, 43.957954 ] ] ] }

少し長くなりましたが、上でやったことを踏まえ、国境データのShapefileをDBにインポートするようなスクリプトを書いてみます。world以下にload.pyというモジュールを作成し、以下のようにします。

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モデルのフィールド、値に国境データのShapefileの持つ属性がマップされています。また今回は座標系を移動させる必要がないため、transform=Falseとします。

このスクリプトを実行してみます。先ほどと同じくDjango Shellを実行します。

$ python3 manage.py shell

続いて、以下のコマンドを叩きます。

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

実行するとSaved:国の名前と出力されるはずです。WorldBorderモデルの中で__str__()を定義しているため、name属性が表示されるようになっています。(__str__()をコメントアウトするとWorldBorder object (〇〇)と出力されます)

Saved: Antigua and Barbuda
Saved: Algeria
Saved: Azerbaijan
Saved: Albania
Saved: Armenia
Saved: Angola
Saved: American Samoa
Saved: Argentina
Saved: Australia
・・・・

ogrinspect

Djangoには、ispectdbという便利なコマンドがあり、これを実行するとDBのmodesl.pyを自動で出力してくれます。GeoDjangoではベクターデータに対応したコマンドとして、ogrinspectというコマンドが用意されています(こちら)。

今回の場合だと、以下のようなコマンドを実行します。

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

結果、国境データのShapefileからそれに合ったmodels.pyの結果を出力してくれます。

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.BigIntegerField()
    region = models.IntegerField()
    subregion = models.IntegerField()
    lon = models.FloatField()
    lat = models.FloatField()
    geom = models.MultiPolygonField(srid=4326)


# Auto-generated `LayerMapping` dictionary for WorldBorder model
worldborder_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',
}

なお、このコマンドはsettings.pyINSTALLED_APPS'django.contrib.gis'を含めておかないと実行できないので注意が必要です。

クエリセットAPI

DjangoのORMには多彩なコマンド(クエリセットAPIと呼ばれています。こちら参照)が用意されています。またこの中で、SQLのWHERE句に相当する機能としてlookupsと呼ばれる構文を指定することができ、これらを利用することでSQLを叩かずとも欲しいクエリセットを取得することができます。

そしてGeoDjangoでは、通常とは別に、GISとしての利用に特化した多彩なlookupsが用意されています(こちら参照)。試しに実行してみます。再度Django Shellを起動します。

$ python3 manage.py shell

起動したら、WKT形式(経度 緯度)で富士山のPOINTを定義します。

>>> pnt_wkt = 'POINT(138.729952 35.359455)'

このPOINTを含んでいるインスタンスのクエリセットを取得してみます。containsというlookups(こちら)を指定します。通常のDjangoでもcontainsというlookupsは存在しますが、GeoDjangoではその地点を含むクエリセットを返してくれます。

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

WKT形式ではなく、GEOSオブジェクト(こちら)としてもクエリセットを取得できます。同じく富士山のPointを定義します。

>>> from django.contrib.gis.geos import Point
>>> pnt = Point(138.729952,35.359455)

次はintersectsというlookups(こちら)を利用してみます。getと組み合わせて、空間的に交差するインスタンスを取得することができます。

>>> WorldBorder.objects.get(mpoly__intersects=pnt)
<WorldBorder: Japan>

最後に富士山から1,000km以内に存在するインスタンスのクエリセットを取得してみます。distance_ltこちら)というlookupsを用いて、距離を基準にフィルタすることができます。

>>> from django.contrib.gis.measure import D
>>> WorldBorder.objects.filter(mpoly__distance_lt=(pnt_wkt, D(km=1000)))
<QuerySet [<WorldBorder: Korea, Republic of>, <WorldBorder: Japan>, <WorldBorder: Korea, Democratic People's Republic of>, <WorldBorder: Russia>]>

このように、GeoDjangoにはとても便利なクエリセットAPIがたくさん用意されています。

座標参照系の自動変換

GeoDjangoでクエリを実行する際、座標参照系の変換も自動的に行ってくれます。srid=3857に指定して、先ほどと同じ富士山の座標を定義します。

>>> from world.models import WorldBorder
>>> from django.contrib.gis.geos import Point
>>> pnt = Point(15443347.614415286, 4212837.5728517035, srid=3857)

この座標を利用して、srid=4326で登録されている今のモデルに対してクエリを叩きます。先ほどと同じ結果が返ってきます。

>>> from django.contrib.gis.measure import D
>>> WorldBorder.objects.filter(mpoly__distance_lt=(pnt, D(km=1000)))
<QuerySet [<WorldBorder: Korea, Republic of>, <WorldBorder: Japan>, <WorldBorder: Korea, Democratic People's Republic of>, <WorldBorder: Russia>]>

内部的には以下のようなSQLが実行されています。DjangoのORMが裏側で変換をしてくれているのがわかります。

>>> qs = WorldBorder.objects.filter(mpoly__distance_lt=(pnt, D(km=1000)))
>>> print(qs.query)
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"::bytea FROM "world_worldborder" WHERE ST_DistanceSphere("world_worldborder"."mpoly", ST_Transform(ST_GeomFromEWKB('\001\001\000\000 \021\017\000\000?J\251s\262tmA1\232\251d\031\022PA'::bytea), 4326)) < 1000000.0

GeoDjangoにおける遅延評価

Djangoではクエリの実行において、実際に値が必要になるまでクエリを叩かない、という最適化手法を取っています。これを遅延評価といいます(参考)。それとは若干異なるのですが、GeoDjangoでは実際にインスタンスのジオメトリフィールドにアクセスした際、初めてオブジェクトが作成されるような仕様になっています。

以下ではjpというインスタンスを取得しています。この際、GeoDjangoはGEOSGeometryオブジェクト(こちら)を作成します。

>>> jp = WorldBorder.objects.get(name='Japan')
>>> jp.mpoly
<MultiPolygon object at 0x7f23279cdd90>

このジオメトリオブジェクトは、様々な地理空間的属性およびメソッドを兼ね備えています。

>>> jp.mpoly.wkt
'MULTIPOLYGON (((153.958588 24.294998, 153.953308 24.292774, 153.946625 24.293331, 153.942749 24.296944, 153.939697 24.300831,
・・・・・
>>> jp.mpoly.geojson
'{ "type": "MultiPolygon", "coordinates": [ [ [ [ 153.958588, 24.294998 ], [ 153.953308, 24.292774 ], [ 153.946625, 24.293331 ], [ 153.942749, 24.296944 ], [ 153.939697, 24.300831 ],
・・・・・
>>> from django.contrib.gis.geos import Point
>>> pnt = Point(138.729952,35.359455)
>>> jp.mpoly.contains(pnt)
True

アドミンページ

Djangoの非常に強力な機能の一つにアドミンページがあります。GeoDjangoでは、このアドミンページに関しても、地理空間的に特化した機能が搭載されています。

さっそく試してみましょう。worldの中のadmin.pyを以下のようにします。django.contrib.adminではなく、django.contrib.gis.adminこちら)をインポートするのがポイントです。

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

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

あとは以下のコマンドでアドミンユーザーを作成します。

$ python3 manage.py createsuperuser

実行が終わったらhttp://localhost:8000/admin/にアクセスします。ユーザー情報を入力してログインし、WorldBorderの任意のオブジェクト編集画面に遷移します。以下のように、Djangoのアドミンページから国境を編集することができます。

test.png

その他ライブラリを導入することで背景マップを変更ができたりします。アドミンページにも様々な機能が実装されています。

おわりに

改めてGeoDjangoを触ってみることで、まだまだたくさんの強力な機能があることに気付けました。今後もGeoDjangoの素晴らしさを紹介していくことができたらと思います。

参考

Django公式ドキュメントのGeoDjangoのページ

GeoDjangoではじめる地理空間情報

7
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?