PostGISへデータインポート

テスト用のGeoJSONファイルをPostGISにインポートします。

使用データ

国土数値情報 ダウンロードサービス - http://nlftp.mlit.go.jp/ksj/index.htmlの北海道のデータを使用します

利用約款 国土数値情報利用約款 - http://nlftp.mlit.go.jp/ksj/other/yakkan.html

GeoJSONに変換をしたファイルの大きさ

  • 国土数値情報 行政区域データ (hokkaido.geojson (63.4MB)

  • 国土数値情報 小学校区データ (elementary_school.geojson (196KB))

  • 国土数値情報 公共施設データ (public_facility.geojson (3.3MB))

  • 国土数値情報 バス停留所データ (busstop.geojson (13.9MB))

一括データダウンロード

GeoJSONデータのモデル構造を調べる

Modelクラスを定義するために、GeoJSONデータの内容を調べてる必要があります。 手動でも構造は調べられますが、管理コマンドの「ogrinspect」を利用して自動で構造を調べます。 ogrinspectコマンドはデータファイルを解析して、モデルで定義出来る形式に自動生成してコンソールに出力します。

ogrinspectコマンド $ python manage.py ogrinspect <データファイル> <モデル名>

注意

  • ogrinspectでGeoJSONデータを調べた場合には”models.CharField(max_length=0)”のようにmax_lengthが0になります。Modelに記述する場合にはmax_lenghに最大値の長さを設定してください。((例)max_length=100)

行政区域データ

(env) $ python manage.py ogrinspect --srid=4326 hokkaido.geojson Border
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
class Border(models.Model):
n03_001 = models.CharField(max_length=0)
n03_002 = models.CharField(max_length=0)
n03_003 = models.CharField(max_length=0)
n03_004 = models.CharField(max_length=0)
n03_007 = models.CharField(max_length=0)
geom = models.PolygonField(srid=4326)

小学校区データ

(env) $ python manage.py ogrinspect --srid=4326 elementary_school.geojson School
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
class School(models.Model):
a27_001 = models.CharField(max_length=0)
a27_002 = models.CharField(max_length=0)
a27_003 = models.CharField(max_length=0)
a27_004 = models.CharField(max_length=0)
geom = models.PointField(srid=4326)

公共施設データ

(env) $ python manage.py ogrinspect --srid=4326 public_facility.geojson Facility
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
class Facility(models.Model):
p02_001 = models.CharField(max_length=0)
p02_002 = models.CharField(max_length=0)
p02_003 = models.CharField(max_length=0)
p02_004 = models.CharField(max_length=0)
p02_005 = models.CharField(max_length=0)
p02_006 = models.CharField(max_length=0)
p02_007 = models.CharField(max_length=0)
geom = models.PointField(srid=4326)

バス停留所データ

(env) $ python manage.py ogrinspect --srid=4326 busstop.geojson Busstop
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
class Busstop(models.Model):
p11_001 = models.CharField(max_length=0)
p11_002 = models.CharField(max_length=0)
p11_003_1 = models.CharField(max_length=0)
p11_003_2 = models.CharField(max_length=0)
p11_003_3 = models.CharField(max_length=0)
p11_003_4 = models.CharField(max_length=0)
p11_003_5 = models.CharField(max_length=0)
p11_003_6 = models.CharField(max_length=0)
p11_003_7 = models.CharField(max_length=0)
p11_003_8 = models.CharField(max_length=0)
p11_003_9 = models.CharField(max_length=0)
p11_003_10 = models.CharField(max_length=0)
p11_003_11 = models.CharField(max_length=0)
p11_003_12 = models.CharField(max_length=0)
p11_003_13 = models.CharField(max_length=0)
p11_003_14 = models.CharField(max_length=0)
p11_003_15 = models.CharField(max_length=0)
p11_003_16 = models.CharField(max_length=0)
p11_003_17 = models.CharField(max_length=0)
p11_003_18 = models.CharField(max_length=0)
p11_003_19 = models.CharField(max_length=0)
p11_004_1 = models.CharField(max_length=0)
p11_004_2 = models.CharField(max_length=0)
p11_004_3 = models.CharField(max_length=0)
p11_004_4 = models.CharField(max_length=0)
p11_004_5 = models.CharField(max_length=0)
p11_004_6 = models.CharField(max_length=0)
p11_004_7 = models.CharField(max_length=0)
p11_004_8 = models.CharField(max_length=0)
p11_004_9 = models.CharField(max_length=0)
p11_004_10 = models.CharField(max_length=0)
p11_004_11 = models.CharField(max_length=0)
p11_004_12 = models.CharField(max_length=0)
p11_004_13 = models.CharField(max_length=0)
p11_004_14 = models.CharField(max_length=0)
p11_004_15 = models.CharField(max_length=0)
p11_004_16 = models.CharField(max_length=0)
p11_004_17 = models.CharField(max_length=0)
p11_004_18 = models.CharField(max_length=0)
p11_004_19 = models.CharField(max_length=0)
geom = models.PointField(srid=4326)

Note

  • コマンドパラメータは「$ python manage.py ogrinspect --help」を入力するとヘルプが表示されます。

GeoJSONデータのモデル定義

worldアプリケーションのmodels.pyに、GeoJSONの定義でを記述します。

  • str() にクラスの名称文字列を定義

  • CharFieldの長さが「max_length=0」になっているので「max_length=50〜256」に変更。シェープファイルではmax_lengthが出力されるがGeoJSONの場合出力されない

(env)$ vi world/models.py
# This is an auto-generated Django model module created by ogrinspect.
from django.contrib.gis.db import models
class Border(models.Model):
n03_001 = models.CharField(max_length=50)
n03_002 = models.CharField(max_length=50)
n03_003 = models.CharField(max_length=50)
n03_004 = models.CharField(max_length=50)
n03_007 = models.CharField(max_length=50)
geom = models.PolygonField(srid=4326)
def __str__(self):
return self.n03_004
class School(models.Model):
a27_001 = models.CharField(max_length=50)
a27_002 = models.CharField(max_length=50)
a27_003 = models.CharField(max_length=50)
a27_004 = models.CharField(max_length=50)
geom = models.PointField(srid=4326)
def __str__(self):
return self.a27_003
class Facility(models.Model):
p02_001 = models.CharField(max_length=50)
p02_002 = models.CharField(max_length=50)
p02_003 = models.CharField(max_length=50)
p02_004 = models.CharField(max_length=50)
p02_005 = models.CharField(max_length=50)
p02_006 = models.CharField(max_length=50)
p02_007 = models.CharField(max_length=50)
geom = models.PointField(srid=4326)
def __str__(self):
return self.p02_004
class Busstop(models.Model):
p11_001 = models.CharField(max_length=256)
p11_002 = models.CharField(max_length=256)
p11_003_1 = models.CharField(max_length=256)
p11_003_2 = models.CharField(max_length=256)
p11_003_3 = models.CharField(max_length=256)
p11_003_4 = models.CharField(max_length=256)
p11_003_5 = models.CharField(max_length=256)
p11_003_6 = models.CharField(max_length=256)
p11_003_7 = models.CharField(max_length=256)
p11_003_8 = models.CharField(max_length=256)
p11_003_9 = models.CharField(max_length=256)
p11_003_10 = models.CharField(max_length=256)
p11_003_11 = models.CharField(max_length=256)
p11_003_12 = models.CharField(max_length=256)
p11_003_13 = models.CharField(max_length=256)
p11_003_14 = models.CharField(max_length=256)
p11_003_15 = models.CharField(max_length=256)
p11_003_16 = models.CharField(max_length=256)
p11_003_17 = models.CharField(max_length=256)
p11_003_18 = models.CharField(max_length=256)
p11_003_19 = models.CharField(max_length=256)
p11_004_1 = models.CharField(max_length=256)
p11_004_2 = models.CharField(max_length=256)
p11_004_3 = models.CharField(max_length=256)
p11_004_4 = models.CharField(max_length=256)
p11_004_5 = models.CharField(max_length=256)
p11_004_6 = models.CharField(max_length=256)
p11_004_7 = models.CharField(max_length=256)
p11_004_8 = models.CharField(max_length=256)
p11_004_9 = models.CharField(max_length=256)
p11_004_10 = models.CharField(max_length=256)
p11_004_11 = models.CharField(max_length=256)
p11_004_12 = models.CharField(max_length=256)
p11_004_13 = models.CharField(max_length=256)
p11_004_14 = models.CharField(max_length=256)
p11_004_15 = models.CharField(max_length=256)
p11_004_16 = models.CharField(max_length=256)
p11_004_17 = models.CharField(max_length=256)
p11_004_18 = models.CharField(max_length=256)
p11_004_19 = models.CharField(max_length=256)
geom = models.PointField(srid=4326)
def __str__(self):
return self.p11_001

モデルのマイグレーションファイルを作成

データベースの更新をするために、マイグレーションファイルを作成します。 makemigrationsは、モデルの変更内容をデータベースに反映するための命令ファイルを作成します。

データベースのマイグレーションファイル作成 $ python manage.py makemigrations

(env) $ python manage.py makemigrations
Migrations for 'world':
world\migrations\0001_initial.py
- Create model Border
- Create model Busstop
- Create model Facility
- Create model School

データベースのテーブル更新

データベースのテーブルを更新します。 migrateは、モデルの変更内容をデータベースに反映します。

データベースのマイグレーション $ python manage.py migrate

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

データインポート

GeoJSONファイルのデータをインポートをするスクリプトファイルを作成し、これを実行してデータをインポートします。 インポートにはユーティリティのdjango.contrib.gis.utils.LayerMappingを利用します。

Note GDALのコマンドラインユーティリティを利用してインポートすることも出来ます。

  • ogr2ogr: GDALのコマンドラインユーティリティ

  • shp2pgsql: ESRI shapefile用のユーティリティ

行政区域データ

行政区域データのインポートスクリプトを作成します

(env) $ vi world/load_hokkaido.py
# -*- coding: utf-8 -*-
import os
from django.contrib.gis.utils import LayerMapping
from world.models import Border
# Modelとファイルのカラムのマッピング
mapping = {
'n03_001' : 'N03_001',
'n03_002' : 'N03_002',
'n03_003' : 'N03_003',
'n03_004' : 'N03_004',
'n03_007' : 'N03_007',
'geom' : 'POLYGON',
}
# ファイルパス
geojson_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'hokkaido.geojson'))
# 実行
def run(verbose=True):
lm = LayerMapping(Border, geojson_file, mapping, transform=False, encoding='UTF-8')
lm.save(strict=True, verbose=verbose)

Djangoのシェルを起動して、ここからインポートスクリプトを実行します。

(env) $ python manage.py shell
>>> from world import load_hokkaido
>>> load_hokkaido.run()
Saved: 小樽市
Saved: 小樽市
>>> exit()

小学校区データ

小学校区データのインポートスクリプトを作成します

(env) $ vi world/load_elementary_school.py
# -*- coding: utf-8 -*-
import os
from django.contrib.gis.utils import LayerMapping
from world.models import School
# Modelとファイルのカラムのマッピング
mapping = {
'a27_001' : 'A27_001',
'a27_002' : 'A27_002',
'a27_003' : 'A27_003',
'a27_004' : 'A27_004',
'geom' : 'POINT',
}
# ファイルパス
geojson_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'elementary_school.geojson'))
# 実行
def run(verbose=True):
lm = LayerMapping(School, geojson_file, mapping, transform=False, encoding='UTF-8')
lm.save(strict=True, verbose=verbose)

Djangoのシェルを起動して、ここからインポートスクリプトを実行します。

(env) $ python manage.py shell
>>> from world import load_elementary_school
>>> load_elementary_school.run()
Saved: 大船小学校
Saved: 高盛小学校
>>> exit()

公共施設データ

公共施設データのインポートスクリプトを作成します

(env) $ vi world/load_public_facility.py
# -*- coding: utf-8 -*-
import os
from django.contrib.gis.utils import LayerMapping
from world.models import Facility
# Modelとファイルのカラムのマッピング
mapping = {
'p02_001' : 'P02_001',
'p02_002' : 'P02_002',
'p02_003' : 'P02_003',
'p02_004' : 'P02_004',
'p02_005' : 'P02_005',
'p02_006' : 'P02_006',
'p02_007' : 'P02_007',
'geom' : 'POINT',
}
# ファイルパス
geojson_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'public_facility.geojson'))
# 実行
def run(verbose=True):
lm = LayerMapping(Facility, geojson_file, mapping, transform=False, encoding='UTF-8')
lm.save(strict=True, verbose=verbose)

Djangoのシェルを起動して、ここからインポートスクリプトを実行します。

(env) $ python manage.py shell
>>> from world import load_public_facility
>>> load_public_facility.run()
Saved: 森町消防本部
Saved: 八雲町消防本部
>>> exit()

バス停留所データ

バス停留所データのインポートスクリプトを作成します

(env) $ vi world/load_busstop.py
# -*- coding: utf-8 -*-
import os
from django.contrib.gis.utils import LayerMapping
from world.models import Busstop
# Modelとファイルのカラムのマッピング
mapping = {
'p11_001' : 'P11_001' ,
'p11_002' : 'P11_002',
'p11_003_1' : 'P11_003_1',
'p11_003_2' : 'P11_003_2',
'p11_003_3' : 'P11_003_3',
'p11_003_4' : 'P11_003_4',
'p11_003_5' : 'P11_003_5',
'p11_003_6' : 'P11_003_6',
'p11_003_7' : 'P11_003_7',
'p11_003_8' : 'P11_003_8',
'p11_003_9' : 'P11_003_9',
'p11_003_10' : 'P11_003_10',
'p11_003_11' : 'P11_003_11',
'p11_003_12' : 'P11_003_12',
'p11_003_13' : 'P11_003_13',
'p11_003_14' : 'P11_003_14',
'p11_003_15' : 'P11_003_15',
'p11_003_16' : 'P11_003_16',
'p11_003_17' : 'P11_003_17',
'p11_003_18' : 'P11_003_18',
'p11_003_19' : 'P11_003_19',
'p11_004_1' : 'P11_004_1',
'p11_004_2' : 'P11_004_2',
'p11_004_3' : 'P11_004_3',
'p11_004_4' : 'P11_004_4',
'p11_004_5' : 'P11_004_5',
'p11_004_6' : 'P11_004_6',
'p11_004_7' : 'P11_004_7',
'p11_004_8' : 'P11_004_8',
'p11_004_9' : 'P11_004_9',
'p11_004_10' : 'P11_004_10',
'p11_004_11' : 'P11_004_11',
'p11_004_12' : 'P11_004_12',
'p11_004_13' : 'P11_004_13',
'p11_004_14' : 'P11_004_14',
'p11_004_15' : 'P11_004_15',
'p11_004_16' : 'P11_004_16',
'p11_004_17' : 'P11_004_17',
'p11_004_18' : 'P11_004_18',
'p11_004_19' : 'P11_004_19',
'geom' : 'POINT',
}
# ファイルパス
geojson_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'busstop.geojson'))
# 実行
def run(verbose=True):
lm = LayerMapping(Busstop, geojson_file, mapping, transform=False, encoding='UTF-8')
lm.save(strict=True, verbose=verbose)

Djangoのシェルを起動して、ここからインポートスクリプトを実行します。

(env) $ python manage.py shell
>>> from world import load_busstop
>>> load_busstop.run()
Saved: 農協入口
Saved: 幕別南町
>>> exit()

管理画面の設定変更

管理画面でマップ表示するように変更をします.

geomフィールドをマップ表示

geomフィールドをマップ表示するように変更します。 (powered by OpenLayers) worldアプリケーションの管理画面の設定を変更します。

(env) $ vi world/admin.py
from django.contrib.gis import admin
from world.models import Border, School, Facility, Busstop
admin.site.register(Border, admin.GeoModelAdmin)
admin.site.register(School, admin.GeoModelAdmin)
admin.site.register(Facility, admin.GeoModelAdmin)
admin.site.register(Busstop, admin.GeoModelAdmin)

URL.confの参照モジュールをGISモジュールに変更します。

(env) $ vi geodjango/urls.py
from django.contrib import admin
from django.contrib.gis import admin

Webサーバを起動します。

(env) $ python manage.py runserver

ブラウザからURL: http://127.0.0.1:8000/admin にアクセスし、ログインした後に表示を確認します。

テーブル一覧が表示されているのを確認します

項目を選択して、geomフィールドがマップ表示されているのを確認します

geomフィールドをOpenStreetMapで表示

背景地図をOpenStreetMapに変更する為に、worldアプリの管理画面の設定を変更します。

(env) $ vi world/admin.py
変更前
admin.site.register(Border, admin.GeoModelAdmin)
admin.site.register(School, admin.GeoModelAdmin)
admin.site.register(Facility, admin.GeoModelAdmin)
admin.site.register(Busstop, admin.GeoModelAdmin)
変更後
admin.site.register(Border, admin.OSMGeoAdmin)
admin.site.register(School, admin.OSMGeoAdmin)
admin.site.register(Facility, admin.OSMGeoAdmin)
admin.site.register(Busstop, admin.OSMGeoAdmin)

OpenStreetMapでマップが表示されているのを確認します

django-leafletで管理画面のマップを表示

管理画面のマップをdjango-leafletで表示をします。

django-leafletをインストール

(env) $ pip install django-leaflet

設定ファイルに追加

(env) $ vi geodjango/settings.py
INSTALLED_APPS = [
:
'leaflet',
]

管理画面設定ファイルを変更

(env) $ vi world/admin.py
変更前
admin.site.register(Border, admin.OSMGeoAdmin)
admin.site.register(School, admin.OSMGeoAdmin)
admin.site.register(Facility, admin.OSMGeoAdmin)
admin.site.register(Busstop, admin.OSMGeoAdmin)
変更後
from leaflet.admin import LeafletGeoAdmin
class BorderAdmin(LeafletGeoAdmin):
search_fields = ['n03_001','n03_003','n03_004']
list_filter = ('n03_003')
admin.site.register(Border, LeafletGeoAdmin)
admin.site.register(School, LeafletGeoAdmin)
admin.site.register(Facility, LeafletGeoAdmin)
admin.site.register(Busstop, LeafletGeoAdmin)

LeafletGeoAdminを登録します。

LeafletGeoAdminを継承したBorderAdminクラスを定義しこれを登録することで、検索・フィルタ機能の追加することが出来ます。

  • search_fields: 検索対象

  • list_filter: フィールド名がフィルタ対象

Note

管理画面をタイトルを変更

設定ファイルのsettings.pyの設定で、管理画面のヘッダとタイトルを変更することが出来ます。

タイトル文字列の設定

(env) $ vi geodjango/settings.py
from django.contrib.gis import admin
admin.site.site_title = 'GeoDjangoログイン'
admin.site.site_header = 'GeoDjangoハンズオン'
admin.site.index_title = 'GeoDjangoメニュー'

または

(env) $ vi geodjango/settings.py
from django.contrib import admin
admin.AdminSite.site_title = 'GeoDjangoログイン'
admin.AdminSite.site_header = 'GeoDjangoハンズオン'
admin.AdminSite.index_title = 'GeoDjangoメニュー'

worldアプリケーションのモデル定義のクラスにメタクラスを追加すると、管理画面のテーブル名称を見やすい形に変更することが出来ます。 テーブル名称は、単数と複数の2種類を指定出来ます。

モデルのタイトル文字列の設定

(env) $ vi world/modles.py
class Border(models.Model):
class Meta:
verbose_name = '行政区域データ' # オブジェクトの人間が読める名前(単数)小文字でよい
verbose_name_plural = '行政区域データ' # オブジェクトの複数の名前 小文字でよい
n03_001 = models.CharField(max_length=50)
n03_002 = models.CharField(max_length=50)
:
:

ログイン画面の例

管理画面のテーブル一覧画面の例