テスト用のGeoJSONファイルをPostGISにインポートします。
国土数値情報 ダウンロードサービス - http://nlftp.mlit.go.jp/ksj/index.htmlの北海道のデータを使用します
国土交通省国土政策局「国土数値情報(行政区域データ)」 (N03-170101_01_GML)
国土交通省国土政策局「国土数値情報(小学校区データ)」 (A27-16_01_GML)
国土交通省国土政策局「国土数値情報(公共施設データ)」 (P02-06_01_GML)
国土交通省国土政策局「国土数値情報(バス停留所データ)」 (P11-10_01_GML)
利用約款 国土数値情報利用約款 - http://nlftp.mlit.go.jp/ksj/other/yakkan.html
国土数値情報 行政区域データ (hokkaido.geojson (63.4MB)
国土数値情報 小学校区データ (elementary_school.geojson (196KB))
国土数値情報 公共施設データ (public_facility.geojson (3.3MB))
国土数値情報 バス停留所データ (busstop.geojson (13.9MB))
一括データダウンロード
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 modelsclass 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 modelsclass 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 modelsclass 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 modelsclass 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」を入力するとヘルプが表示されます。
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 modelsclass 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_004class 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_003class 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_004class 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 makemigrationsMigrations 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 migrateOperations to perform:Apply all migrations: admin, auth, contenttypes, sessions, worldRunning 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 osfrom django.contrib.gis.utils import LayerMappingfrom 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 osfrom django.contrib.gis.utils import LayerMappingfrom 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 osfrom django.contrib.gis.utils import LayerMappingfrom 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 osfrom django.contrib.gis.utils import LayerMappingfrom 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フィールドをマップ表示するように変更します。 (powered by OpenLayers) worldアプリケーションの管理画面の設定を変更します。
(env) $ vi world/admin.pyfrom django.contrib.gis import adminfrom world.models import Border, School, Facility, Busstopadmin.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.pyfrom 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フィールドがマップ表示されているのを確認します
背景地図を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をインストール
(env) $ pip install django-leaflet
設定ファイルに追加
(env) $ vi geodjango/settings.pyINSTALLED_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 LeafletGeoAdminclass 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
django-leafletは管理画面以外にもいろいろな機能がありますので下記を参考にしてみて下さい。
django-leaflet - https://github.com/makinacorpus/django-leaflet
設定ファイルのsettings.pyの設定で、管理画面のヘッダとタイトルを変更することが出来ます。
タイトル文字列の設定
(env) $ vi geodjango/settings.pyfrom django.contrib.gis import adminadmin.site.site_title = 'GeoDjangoログイン'admin.site.site_header = 'GeoDjangoハンズオン'admin.site.index_title = 'GeoDjangoメニュー'
または
(env) $ vi geodjango/settings.pyfrom django.contrib import adminadmin.AdminSite.site_title = 'GeoDjangoログイン'admin.AdminSite.site_header = 'GeoDjangoハンズオン'admin.AdminSite.index_title = 'GeoDjangoメニュー'
worldアプリケーションのモデル定義のクラスにメタクラスを追加すると、管理画面のテーブル名称を見やすい形に変更することが出来ます。 テーブル名称は、単数と複数の2種類を指定出来ます。
モデルのタイトル文字列の設定
(env) $ vi world/modles.pyclass Border(models.Model):class Meta:verbose_name = '行政区域データ' # オブジェクトの人間が読める名前(単数)小文字でよいverbose_name_plural = '行政区域データ' # オブジェクトの複数の名前 小文字でよいn03_001 = models.CharField(max_length=50)n03_002 = models.CharField(max_length=50)::
ログイン画面の例
管理画面のテーブル一覧画面の例