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)
行政区域データ
1
(env) $ python manage.py ogrinspect --srid=4326 hokkaido.geojson Border
2
# This is an auto-generated Django model module created by ogrinspect.
3
from django.contrib.gis.db import models
4
5
class Border(models.Model):
6
n03_001 = models.CharField(max_length=0)
7
n03_002 = models.CharField(max_length=0)
8
n03_003 = models.CharField(max_length=0)
9
n03_004 = models.CharField(max_length=0)
10
n03_007 = models.CharField(max_length=0)
11
geom = models.PolygonField(srid=4326)
Copied!
小学校区データ
1
(env) $ python manage.py ogrinspect --srid=4326 elementary_school.geojson School
2
# This is an auto-generated Django model module created by ogrinspect.
3
from django.contrib.gis.db import models
4
5
class School(models.Model):
6
a27_001 = models.CharField(max_length=0)
7
a27_002 = models.CharField(max_length=0)
8
a27_003 = models.CharField(max_length=0)
9
a27_004 = models.CharField(max_length=0)
10
geom = models.PointField(srid=4326)
Copied!
公共施設データ
1
(env) $ python manage.py ogrinspect --srid=4326 public_facility.geojson Facility
2
# This is an auto-generated Django model module created by ogrinspect.
3
from django.contrib.gis.db import models
4
5
class Facility(models.Model):
6
p02_001 = models.CharField(max_length=0)
7
p02_002 = models.CharField(max_length=0)
8
p02_003 = models.CharField(max_length=0)
9
p02_004 = models.CharField(max_length=0)
10
p02_005 = models.CharField(max_length=0)
11
p02_006 = models.CharField(max_length=0)
12
p02_007 = models.CharField(max_length=0)
13
geom = models.PointField(srid=4326)
Copied!
バス停留所データ
1
(env) $ python manage.py ogrinspect --srid=4326 busstop.geojson Busstop
2
# This is an auto-generated Django model module created by ogrinspect.
3
from django.contrib.gis.db import models
4
5
class Busstop(models.Model):
6
p11_001 = models.CharField(max_length=0)
7
p11_002 = models.CharField(max_length=0)
8
p11_003_1 = models.CharField(max_length=0)
9
p11_003_2 = models.CharField(max_length=0)
10
p11_003_3 = models.CharField(max_length=0)
11
p11_003_4 = models.CharField(max_length=0)
12
p11_003_5 = models.CharField(max_length=0)
13
p11_003_6 = models.CharField(max_length=0)
14
p11_003_7 = models.CharField(max_length=0)
15
p11_003_8 = models.CharField(max_length=0)
16
p11_003_9 = models.CharField(max_length=0)
17
p11_003_10 = models.CharField(max_length=0)
18
p11_003_11 = models.CharField(max_length=0)
19
p11_003_12 = models.CharField(max_length=0)
20
p11_003_13 = models.CharField(max_length=0)
21
p11_003_14 = models.CharField(max_length=0)
22
p11_003_15 = models.CharField(max_length=0)
23
p11_003_16 = models.CharField(max_length=0)
24
p11_003_17 = models.CharField(max_length=0)
25
p11_003_18 = models.CharField(max_length=0)
26
p11_003_19 = models.CharField(max_length=0)
27
p11_004_1 = models.CharField(max_length=0)
28
p11_004_2 = models.CharField(max_length=0)
29
p11_004_3 = models.CharField(max_length=0)
30
p11_004_4 = models.CharField(max_length=0)
31
p11_004_5 = models.CharField(max_length=0)
32
p11_004_6 = models.CharField(max_length=0)
33
p11_004_7 = models.CharField(max_length=0)
34
p11_004_8 = models.CharField(max_length=0)
35
p11_004_9 = models.CharField(max_length=0)
36
p11_004_10 = models.CharField(max_length=0)
37
p11_004_11 = models.CharField(max_length=0)
38
p11_004_12 = models.CharField(max_length=0)
39
p11_004_13 = models.CharField(max_length=0)
40
p11_004_14 = models.CharField(max_length=0)
41
p11_004_15 = models.CharField(max_length=0)
42
p11_004_16 = models.CharField(max_length=0)
43
p11_004_17 = models.CharField(max_length=0)
44
p11_004_18 = models.CharField(max_length=0)
45
p11_004_19 = models.CharField(max_length=0)
46
geom = models.PointField(srid=4326)
Copied!
Note
  • コマンドパラメータは「$ python manage.py ogrinspect --help」を入力するとヘルプが表示されます。

GeoJSONデータのモデル定義

worldアプリケーションのmodels.pyに、GeoJSONの定義でを記述します。
  • str() にクラスの名称文字列を定義
  • CharFieldの長さが「max_length=0」になっているので「max_length=50〜256」に変更。シェープファイルではmax_lengthが出力されるがGeoJSONの場合出力されない
1
(env)$ vi world/models.py
2
# This is an auto-generated Django model module created by ogrinspect.
3
from django.contrib.gis.db import models
4
5
class Border(models.Model):
6
n03_001 = models.CharField(max_length=50)
7
n03_002 = models.CharField(max_length=50)
8
n03_003 = models.CharField(max_length=50)
9
n03_004 = models.CharField(max_length=50)
10
n03_007 = models.CharField(max_length=50)
11
geom = models.PolygonField(srid=4326)
12
13
def __str__(self):
14
return self.n03_004
15
16
class School(models.Model):
17
a27_001 = models.CharField(max_length=50)
18
a27_002 = models.CharField(max_length=50)
19
a27_003 = models.CharField(max_length=50)
20
a27_004 = models.CharField(max_length=50)
21
geom = models.PointField(srid=4326)
22
23
def __str__(self):
24
return self.a27_003
25
26
class Facility(models.Model):
27
p02_001 = models.CharField(max_length=50)
28
p02_002 = models.CharField(max_length=50)
29
p02_003 = models.CharField(max_length=50)
30
p02_004 = models.CharField(max_length=50)
31
p02_005 = models.CharField(max_length=50)
32
p02_006 = models.CharField(max_length=50)
33
p02_007 = models.CharField(max_length=50)
34
geom = models.PointField(srid=4326)
35
36
def __str__(self):
37
return self.p02_004
38
39
class Busstop(models.Model):
40
p11_001 = models.CharField(max_length=256)
41
p11_002 = models.CharField(max_length=256)
42
p11_003_1 = models.CharField(max_length=256)
43
p11_003_2 = models.CharField(max_length=256)
44
p11_003_3 = models.CharField(max_length=256)
45
p11_003_4 = models.CharField(max_length=256)
46
p11_003_5 = models.CharField(max_length=256)
47
p11_003_6 = models.CharField(max_length=256)
48
p11_003_7 = models.CharField(max_length=256)
49
p11_003_8 = models.CharField(max_length=256)
50
p11_003_9 = models.CharField(max_length=256)
51
p11_003_10 = models.CharField(max_length=256)
52
p11_003_11 = models.CharField(max_length=256)
53
p11_003_12 = models.CharField(max_length=256)
54
p11_003_13 = models.CharField(max_length=256)
55
p11_003_14 = models.CharField(max_length=256)
56
p11_003_15 = models.CharField(max_length=256)
57
p11_003_16 = models.CharField(max_length=256)
58
p11_003_17 = models.CharField(max_length=256)
59
p11_003_18 = models.CharField(max_length=256)
60
p11_003_19 = models.CharField(max_length=256)
61
p11_004_1 = models.CharField(max_length=256)
62
p11_004_2 = models.CharField(max_length=256)
63
p11_004_3 = models.CharField(max_length=256)
64
p11_004_4 = models.CharField(max_length=256)
65
p11_004_5 = models.CharField(max_length=256)
66
p11_004_6 = models.CharField(max_length=256)
67
p11_004_7 = models.CharField(max_length=256)
68
p11_004_8 = models.CharField(max_length=256)
69
p11_004_9 = models.CharField(max_length=256)
70
p11_004_10 = models.CharField(max_length=256)
71
p11_004_11 = models.CharField(max_length=256)
72
p11_004_12 = models.CharField(max_length=256)
73
p11_004_13 = models.CharField(max_length=256)
74
p11_004_14 = models.CharField(max_length=256)
75
p11_004_15 = models.CharField(max_length=256)
76
p11_004_16 = models.CharField(max_length=256)
77
p11_004_17 = models.CharField(max_length=256)
78
p11_004_18 = models.CharField(max_length=256)
79
p11_004_19 = models.CharField(max_length=256)
80
geom = models.PointField(srid=4326)
81
82
def __str__(self):
83
return self.p11_001
Copied!

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

データベースの更新をするために、マイグレーションファイルを作成します。 makemigrationsは、モデルの変更内容をデータベースに反映するための命令ファイルを作成します。
データベースのマイグレーションファイル作成 $ python manage.py makemigrations
1
(env) $ python manage.py makemigrations
2
Migrations for 'world':
3
world\migrations\0001_initial.py
4
- Create model Border
5
- Create model Busstop
6
- Create model Facility
7
- Create model School
Copied!

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

データベースのテーブルを更新します。 migrateは、モデルの変更内容をデータベースに反映します。
データベースのマイグレーション $ python manage.py migrate
1
(env) $ python manage.py migrate
2
Operations to perform:
3
Apply all migrations: admin, auth, contenttypes, sessions, world
4
Running migrations:
5
Applying world.0001_initial... OK
Copied!

データインポート

GeoJSONファイルのデータをインポートをするスクリプトファイルを作成し、これを実行してデータをインポートします。 インポートにはユーティリティのdjango.contrib.gis.utils.LayerMappingを利用します。
Note GDALのコマンドラインユーティリティを利用してインポートすることも出来ます。
  • ogr2ogr: GDALのコマンドラインユーティリティ
  • shp2pgsql: ESRI shapefile用のユーティリティ

行政区域データ

行政区域データのインポートスクリプトを作成します
1
(env) $ vi world/load_hokkaido.py
2
# -*- coding: utf-8 -*-
3
import os
4
from django.contrib.gis.utils import LayerMapping
5
from world.models import Border
6
7
# Modelとファイルのカラムのマッピング
8
mapping = {
9
'n03_001' : 'N03_001',
10
'n03_002' : 'N03_002',
11
'n03_003' : 'N03_003',
12
'n03_004' : 'N03_004',
13
'n03_007' : 'N03_007',
14
'geom' : 'POLYGON',
15
}
16
17
# ファイルパス
18
geojson_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'hokkaido.geojson'))
19
20
# 実行
21
def run(verbose=True):
22
lm = LayerMapping(Border, geojson_file, mapping, transform=False, encoding='UTF-8')
23
lm.save(strict=True, verbose=verbose)
Copied!
Djangoのシェルを起動して、ここからインポートスクリプトを実行します。
1
(env) $ python manage.py shell
2
>>> from world import load_hokkaido
3
>>> load_hokkaido.run()
4
5
Saved: 小樽市
6
Saved: 小樽市
7
8
>>> exit()
Copied!

小学校区データ

小学校区データのインポートスクリプトを作成します
1
(env) $ vi world/load_elementary_school.py
2
# -*- coding: utf-8 -*-
3
import os
4
from django.contrib.gis.utils import LayerMapping
5
from world.models import School
6
7
# Modelとファイルのカラムのマッピング
8
mapping = {
9
'a27_001' : 'A27_001',
10
'a27_002' : 'A27_002',
11
'a27_003' : 'A27_003',
12
'a27_004' : 'A27_004',
13
'geom' : 'POINT',
14
}
15
16
# ファイルパス
17
geojson_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'elementary_school.geojson'))
18
19
# 実行
20
def run(verbose=True):
21
lm = LayerMapping(School, geojson_file, mapping, transform=False, encoding='UTF-8')
22
lm.save(strict=True, verbose=verbose)
Copied!
Djangoのシェルを起動して、ここからインポートスクリプトを実行します。
1
(env) $ python manage.py shell
2
>>> from world import load_elementary_school
3
>>> load_elementary_school.run()
4
Saved: 大船小学校
5
Saved: 高盛小学校
6
7
>>> exit()
Copied!

公共施設データ

公共施設データのインポートスクリプトを作成します
1
(env) $ vi world/load_public_facility.py
2
# -*- coding: utf-8 -*-
3
import os
4
from django.contrib.gis.utils import LayerMapping
5
from world.models import Facility
6
7
# Modelとファイルのカラムのマッピング
8
mapping = {
9
'p02_001' : 'P02_001',
10
'p02_002' : 'P02_002',
11
'p02_003' : 'P02_003',
12
'p02_004' : 'P02_004',
13
'p02_005' : 'P02_005',
14
'p02_006' : 'P02_006',
15
'p02_007' : 'P02_007',
16
'geom' : 'POINT',
17
}
18
19
# ファイルパス
20
geojson_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'public_facility.geojson'))
21
22
# 実行
23
def run(verbose=True):
24
lm = LayerMapping(Facility, geojson_file, mapping, transform=False, encoding='UTF-8')
25
lm.save(strict=True, verbose=verbose)
Copied!
Djangoのシェルを起動して、ここからインポートスクリプトを実行します。
1
(env) $ python manage.py shell
2
>>> from world import load_public_facility
3
>>> load_public_facility.run()
4
5
Saved: 森町消防本部
6
Saved: 八雲町消防本部
7
8
>>> exit()
Copied!

バス停留所データ

バス停留所データのインポートスクリプトを作成します
1
(env) $ vi world/load_busstop.py
2
# -*- coding: utf-8 -*-
3
import os
4
from django.contrib.gis.utils import LayerMapping
5
from world.models import Busstop
6
7
# Modelとファイルのカラムのマッピング
8
mapping = {
9
'p11_001' : 'P11_001' ,
10
'p11_002' : 'P11_002',
11
'p11_003_1' : 'P11_003_1',
12
'p11_003_2' : 'P11_003_2',
13
'p11_003_3' : 'P11_003_3',
14
'p11_003_4' : 'P11_003_4',
15
'p11_003_5' : 'P11_003_5',
16
'p11_003_6' : 'P11_003_6',
17
'p11_003_7' : 'P11_003_7',
18
'p11_003_8' : 'P11_003_8',
19
'p11_003_9' : 'P11_003_9',
20
'p11_003_10' : 'P11_003_10',
21
'p11_003_11' : 'P11_003_11',
22
'p11_003_12' : 'P11_003_12',
23
'p11_003_13' : 'P11_003_13',
24
'p11_003_14' : 'P11_003_14',
25
'p11_003_15' : 'P11_003_15',
26
'p11_003_16' : 'P11_003_16',
27
'p11_003_17' : 'P11_003_17',
28
'p11_003_18' : 'P11_003_18',
29
'p11_003_19' : 'P11_003_19',
30
'p11_004_1' : 'P11_004_1',
31
'p11_004_2' : 'P11_004_2',
32
'p11_004_3' : 'P11_004_3',
33
'p11_004_4' : 'P11_004_4',
34
'p11_004_5' : 'P11_004_5',
35
'p11_004_6' : 'P11_004_6',
36
'p11_004_7' : 'P11_004_7',
37
'p11_004_8' : 'P11_004_8',
38
'p11_004_9' : 'P11_004_9',
39
'p11_004_10' : 'P11_004_10',
40
'p11_004_11' : 'P11_004_11',
41
'p11_004_12' : 'P11_004_12',
42
'p11_004_13' : 'P11_004_13',
43
'p11_004_14' : 'P11_004_14',
44
'p11_004_15' : 'P11_004_15',
45
'p11_004_16' : 'P11_004_16',
46
'p11_004_17' : 'P11_004_17',
47
'p11_004_18' : 'P11_004_18',
48
'p11_004_19' : 'P11_004_19',
49
'geom' : 'POINT',
50
}
51
52
# ファイルパス
53
geojson_file = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data', 'busstop.geojson'))
54
55
# 実行
56
def run(verbose=True):
57
lm = LayerMapping(Busstop, geojson_file, mapping, transform=False, encoding='UTF-8')
58
lm.save(strict=True, verbose=verbose)
Copied!
Djangoのシェルを起動して、ここからインポートスクリプトを実行します。
1
(env) $ python manage.py shell
2
>>> from world import load_busstop
3
>>> load_busstop.run()
4
5
Saved: 農協入口
6
Saved: 幕別南町
7
8
>>> exit()
Copied!

管理画面の設定変更

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

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

geomフィールドをマップ表示するように変更します。 (powered by OpenLayers) worldアプリケーションの管理画面の設定を変更します。
1
(env) $ vi world/admin.py
2
from django.contrib.gis import admin
3
from world.models import Border, School, Facility, Busstop
4
5
admin.site.register(Border, admin.GeoModelAdmin)
6
admin.site.register(School, admin.GeoModelAdmin)
7
admin.site.register(Facility, admin.GeoModelAdmin)
8
admin.site.register(Busstop, admin.GeoModelAdmin)
Copied!
URL.confの参照モジュールをGISモジュールに変更します。
1
(env) $ vi geodjango/urls.py
2
from django.contrib import admin
3
4
from django.contrib.gis import admin
Copied!
Webサーバを起動します。
1
(env) $ python manage.py runserver
Copied!
ブラウザからURL: http://127.0.0.1:8000/admin にアクセスし、ログインした後に表示を確認します。
テーブル一覧が表示されているのを確認します
項目を選択して、geomフィールドがマップ表示されているのを確認します

geomフィールドをOpenStreetMapで表示

背景地図をOpenStreetMapに変更する為に、worldアプリの管理画面の設定を変更します。
1
(env) $ vi world/admin.py
2
変更前
3
admin.site.register(Border, admin.GeoModelAdmin)
4
admin.site.register(School, admin.GeoModelAdmin)
5
admin.site.register(Facility, admin.GeoModelAdmin)
6
admin.site.register(Busstop, admin.GeoModelAdmin)
7
8
変更後
9
admin.site.register(Border, admin.OSMGeoAdmin)
10
admin.site.register(School, admin.OSMGeoAdmin)
11
admin.site.register(Facility, admin.OSMGeoAdmin)
12
admin.site.register(Busstop, admin.OSMGeoAdmin)
Copied!
OpenStreetMapでマップが表示されているのを確認します

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

管理画面のマップをdjango-leafletで表示をします。
django-leafletをインストール
1
(env) $ pip install django-leaflet
Copied!
設定ファイルに追加
1
(env) $ vi geodjango/settings.py
2
INSTALLED_APPS = [
3
:
4
'leaflet',
5
]
Copied!
管理画面設定ファイルを変更
1
(env) $ vi world/admin.py
2
変更前
3
admin.site.register(Border, admin.OSMGeoAdmin)
4
admin.site.register(School, admin.OSMGeoAdmin)
5
admin.site.register(Facility, admin.OSMGeoAdmin)
6
admin.site.register(Busstop, admin.OSMGeoAdmin)
7
8
変更後
9
from leaflet.admin import LeafletGeoAdmin
10
11
class BorderAdmin(LeafletGeoAdmin):
12
search_fields = ['n03_001','n03_003','n03_004']
13
list_filter = ('n03_003')
14
15
admin.site.register(Border, LeafletGeoAdmin)
16
admin.site.register(School, LeafletGeoAdmin)
17
admin.site.register(Facility, LeafletGeoAdmin)
18
admin.site.register(Busstop, LeafletGeoAdmin)
Copied!
LeafletGeoAdminを登録します。
LeafletGeoAdminを継承したBorderAdminクラスを定義しこれを登録することで、検索・フィルタ機能の追加することが出来ます。
  • search_fields: 検索対象
  • list_filter: フィールド名がフィルタ対象
Note

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

設定ファイルのsettings.pyの設定で、管理画面のヘッダとタイトルを変更することが出来ます。
タイトル文字列の設定
1
(env) $ vi geodjango/settings.py
2
from django.contrib.gis import admin
3
4
admin.site.site_title = 'GeoDjangoログイン'
5
admin.site.site_header = 'GeoDjangoハンズオン'
6
admin.site.index_title = 'GeoDjangoメニュー'
Copied!
または
1
(env) $ vi geodjango/settings.py
2
from django.contrib import admin
3
4
admin.AdminSite.site_title = 'GeoDjangoログイン'
5
admin.AdminSite.site_header = 'GeoDjangoハンズオン'
6
admin.AdminSite.index_title = 'GeoDjangoメニュー'
Copied!
worldアプリケーションのモデル定義のクラスにメタクラスを追加すると、管理画面のテーブル名称を見やすい形に変更することが出来ます。 テーブル名称は、単数と複数の2種類を指定出来ます。
モデルのタイトル文字列の設定
1
(env) $ vi world/modles.py
2
class Border(models.Model):
3
class Meta:
4
verbose_name = '行政区域データ' # オブジェクトの人間が読める名前(単数)小文字でよい
5
verbose_name_plural = '行政区域データ' # オブジェクトの複数の名前 小文字でよい
6
7
n03_001 = models.CharField(max_length=50)
8
n03_002 = models.CharField(max_length=50)
9
:
10
:
Copied!
ログイン画面の例
管理画面のテーブル一覧画面の例