前回でようやくPostGISとGeoDjangoのインストールが完了しましたので、それでは早速Djangoを使ってみましょう。ただ、今回はDjangoと言っても、GeoDjangoなので、できればデータがあったほうがいいですよね。ということで、国民の味方、国土交通省の国土数値情報を使わせて頂くことにしましょう。
データの準備
データの入手
以下のページから「行政区域」をダウンロードして利用させて頂きました。
私は全国(N03-14-140401)で試していますが、必要に応じて各都道府県版でも動作上問題はありませんのでお好きなモノを選択ください。
Djangoアプリをつくる
先に申し上げておきますが、Django使うの初めてです。ですので色々イケてないやり方や説明に不備があるかとおもいますが、とりあえず動きはするので信じてついてきてください。
プロジェクト作成
任意のディレクトリで以下コマンドを叩くと、次のようなファイルが自動生成されます。
$ django-admin.py startproject geodjango $ tree -c geodjango geodjango ├── geodjango │ ├── __init__.pyc │ ├── settings.pyc │ ├── settings.py │ ├── __init__.py │ ├── urls.py │ └── wsgi.py └── manage.py
アプリ作成
先程作成したgeodjangoディレクトリに移動してアプリを「demo」という名前で作成します。するとアプリ名のディレクトリが作成され、作成したディレクトリ配下に次のようなファイルが自動生成されます。
$ cd geodjango/ $ python manage.py startapp demo $ ls -F demo/ geodjango/ manage.py* $ tree -c demo demo ├── __init__.py ├── admin.py ├── migrations │ └── __init__.py ├── models.py ├── tests.py └── views.py
なお、一つのdjangoプロジェクト内に複数アプリを作成してURLマッピングで同時に利用できるので、ここでいうアプリはWebアプリの一つのモジュールなイメージっぽいです。
GeoDjango用にプロジェクト設定を変更する
Djangoのプロジェクト設定を編集します。なお、以下の日本語コメントをそのまま貼り付けると文字コードでエラーになるので除去するかファイルの行頭に「# -*- coding: utf-8 -*-」を追加してください。
$ vi geodjango/settings.py
# postgisの設定変更する DATABASES = { 'default': { 'ENGINE': 'django.contrib.gis.db.backends.postgis', 'NAME': 'geodjangodb', 'USER': 'geodjango', # 前回作成DBユーザの名前 'PASSWORD': '*****', # 前回作成DBユーザのパスワード } } # 以下の2行を追加 INSTALLED_APPS = ( 'django.contrib.gis', # 既存定義の最後に追加 'demo', # 既存定義の最後に追加 ) # 日本向けに変更(お好みで) LANGUAGE_CODE = 'ja' # 値を変更 TIME_ZONE = 'Asia/Tokyo' # 値を変更
Shapefileのインポート
先程ダウンロードして加工したデータ(Shapefile)をもとにモデルクラスを作成し、ShapefileのデータをDBにインポートします。ちょっと長いですがココが今回の一番重要なところです。
まずはdemo配下にdataディレクトリを作成します。
$ mkdir demo/data
上記ディレクトリにダウンロードしたzipファイル展開後のファイル一式をscp等で転送してください。
$ ls demo/data/ KS-META-N03-14_140401.xml N03-14_140401.sbn N03-14_140401.shx N03-14_140401.dbf N03-14_140401.sbx N03-14_140401.xml N03-14_140401.prj N03-14_140401.shp
こんな種類のファイルがあればOKです。
1.Shapefileの頂点数を減らす
ダウンロードしてきたShapefileをそのまま利用するのでもいいのですが、ポリゴンの頂点数が多いのでそのまま扱うと地図表示の時などに重くなるので楽しくありません。今回は精度は特に考えずにサクサク試したいので、頂点数を減らしましょう。
$ cd demo/data $ ogr2ogr N03-14_140401_Simply.shp N03-14_140401.shp -simplify 0.0001 -lco ENCODING=932
コマンドが完了すると以下のようなファイルが増えています。こちらが簡素化されたShapefileになります。
$ ls *Simply* N03-14_140401_Simply.cpg N03-14_140401_Simply.prj N03-14_140401_Simply.shx N03-14_140401_Simply.dbf N03-14_140401_Simply.shp
2.Shapefileの構造確認
ここで、モデルクラスを定義するためにShapefileの構造を確認します。
$ ogrinfo N03-14_140401_Simply.shp INFO: Open of `N03-14_140401_Simply.shp' using driver `ESRI Shapefile' successful. 1: N03-14_140401_Simply (Polygon)
$ ogrinfo -so N03-14_140401_Simply.shp N03-14_140401_Simply INFO: Open of `N03-14_140401_Simply.shp' using driver `ESRI Shapefile' successful. Layer name: N03-14_140401_Simply Geometry: Polygon Feature Count: 73274 Extent: (122.933665, 20.425127) - (153.986893, 45.557667) Layer SRS WKT: GEOGCS["GCS_JGD_2000", DATUM["Japanese_Geodetic_Datum_2000", SPHEROID["GRS_1980",6378137.0,298.257222101]], PRIMEM["Greenwich",0.0], UNIT["Degree",0.017453292519943295]] N03_001: String (10.0) N03_002: String (20.0) N03_003: String (20.0) N03_004: String (20.0) N03_007: String (5.0)
3.モデルクラスの作成
今度は構造に合わせてモデルクラスを定義します。先程の出力結果を見ながら手動で作成してもいいのですが、自動で生成してみましょう(前回記事の修正前の段階でDB作成している場合は、ogrinspectで失敗します。申し訳ありませんが、以下のカスタマイズ後のものを貼り付けるか、DB削除後、修正後記事内容でひな形作成から行うようにお願いします)。
$ python manage.py ogrinspect --srid=4612 demo/data/N03-14_140401_Simply.shp Border > demo/models.py $ vi demo/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=10) n03_002 = models.CharField(max_length=20) n03_003 = models.CharField(max_length=20) n03_004 = models.CharField(max_length=20) n03_007 = models.CharField(max_length=5) geom = models.PolygonField(srid=4612) objects = models.GeoManager()
自動生成されたものをベースに修正します。
# -*- coding: utf-8 -*- # 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(u'都道府県名', max_length=10) n03_002 = models.CharField(u'支庁名', max_length=20, blank=True) n03_003 = models.CharField(u'群・政令市名', max_length=20, blank=True) n03_004 = models.CharField(u'市区町村名', max_length=20, blank=True) n03_007 = models.CharField(u'行政区域コード', max_length=5) geom = models.PolygonField(srid=4612) objects = models.GeoManager() def __unicode__(self): return "%s_%s_%s(%s)" % (self.n03_001,self.n03_003,self.n03_004,self.n03_007) class Meta: verbose_name = u"行政区域" verbose_name_plural = u"行政区域一覧"
変更内容は以下のとおりです。
・日本語を扱うので公式チュートリアルの「__str__()」の代わりに「__unicode__()」を定義
・元データでは空白になるフィールドがあるので空白許容を追加
・各フィールドのフォームに用いられるラベルを追加
・管理画面用にMetaクラスを定義
4.DBにモデルを反映
作成したモデルからDBに各種テーブルを作成します。
$ python manage.py makemigrations Migrations for 'demo': 0001_initial.py: - Create model Border $ python manage.py migrate Operations to perform: Synchronize unmigrated apps: gis Apply all migrations: admin, demo, contenttypes, auth, sessions Synchronizing apps without migrations: Creating tables... Installing custom SQL... Installing indexes... Running migrations: Applying contenttypes.0001_initial... OK Applying auth.0001_initial... OK Applying admin.0001_initial... OK Applying demo.0001_initial... OK Applying sessions.0001_initial... OK
本当に出来てるか念のため確認しましょう。
$psql geodjangodb -U geodjango ユーザ geodjango のパスワード:**** psql (9.3.5) "help" でヘルプを表示します. geodjangodb=> \dt リレーションの一覧 スキーマ | 名前 | 型 | 所有者 ----------+----------------------------+----------+----------- public | auth_group | テーブル | geodjango public | auth_group_permissions | テーブル | geodjango public | auth_permission | テーブル | geodjango public | auth_user | テーブル | geodjango public | auth_user_groups | テーブル | geodjango public | auth_user_user_permissions | テーブル | geodjango public | demo_border | テーブル | geodjango public | django_admin_log | テーブル | geodjango public | django_content_type | テーブル | geodjango public | django_migrations | テーブル | geodjango public | django_session | テーブル | geodjango public | spatial_ref_sys | テーブル | postgres (12 行) geodjangodb=> \d demo_border テーブル "public.demo_border" 列 | 型 | 修飾語 ---------+------------------------+---------------------------------------------------------- id | integer | not null default nextval('demo_border_id_seq'::regclass) n03_001 | character varying(10) | not null n03_002 | character varying(20) | not null n03_003 | character varying(20) | not null n03_004 | character varying(20) | not null n03_007 | character varying(5) | not null geom | geometry(Polygon,4612) | not null インデックス: "demo_border_pkey" PRIMARY KEY, btree (id) "demo_border_geom_id" gist (geom) geodjangodb=>\q
それっぽいのができてますね。
5.DBにデータを登録
テーブルができたので早速データを登録します。
インタラクティブにやってもいいですが、Shapefile投入用の処理を書きましょう。
$ vi demo/load.py
# -*- coding: utf-8 -*- import os from django.contrib.gis.utils import LayerMapping from demo.models import Border # モデルクラスとShapefileのカラムのマッピング border_mapping = { 'n03_001' : 'N03_001', 'n03_002' : 'N03_002', 'n03_003' : 'N03_003', 'n03_004' : 'N03_004', 'n03_007' : 'N03_007', 'geom' : 'POLYGON', } # ロード対象のShapefile border_shp = os.path.abspath(os.path.join(os.path.dirname(__file__), 'data/N03-14_140401_Simply.shp')) def run(verbose=True): lm = LayerMapping(Border, border_shp, border_mapping, transform=False, encoding='utf-8') lm.save(strict=True, verbose=verbose)
この関数を管理シェルで実行します。
$ python manage.py shell Python 2.7.6 (default, Mar 22 2014, 22:59:56) Type "copyright", "credits" or "license" for more information. IPython 2.3.1 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]: from demo import load In [2]: load.run() # Saved: XXXX が出力される(登録件数分) In [3]: exit
さて、ちゃんと登録されたかDBを見てみましょう。
$ psql geodjangodb -U geodjango ユーザ geodjango のパスワード:**** psql (9.3.5) "help" でヘルプを表示します. geodjangodb=> select count(*) from demo_border; count ------- 73274 (1 行) geodjangodb=>\q
全国分なので73274件入りました。
さてこれでようやくデータ登録が完了したので、次回は管理画面を使ってデータを確認してみましょう。