Django Rest Frameworkで位置情報モデルを扱う

Django + PostgreSQL環境で位置情報を扱うのに、PostGIS拡張した上でpipのdjango-location-fieldを使うのが同時生成される管理画面的にも易しかったので共有。

準備

Githubはこちら

pip install django-location-field

インストールが無事完了したら、settings.pyにてアプリケーションの追加をします。

INSTALLED_APPS = [
  ...
  'location_field.apps.DefaultConfig',
]

これで各MTVの各層で使用可能になります。

※今回はDRFなのでMVのみになります。

PostGIS拡張について

本記事ではミドルウェアの設定周りは思い切り端折ってます。

コマンドや設定ファイルをコピペで済ますと割と泥沼化しかねないので・・・

その代わりに確認事項を挙げておきます。

  • PostgreSQLとPostGISのバージョンの整合性
  • pg_hba.confの設定内容
  • データベースのエクステンション作成(create extension postgis;が通っているか)
  • アプリケーションの所有者設定は適切か(適切でないと権限で弾かれたりします)
  • Webサーバーの設定は適切か

もしブラウザで確認した際、Internal Errorが出る場合はこれらのどこかがうまくいっていないのかも知れません。

INSTALLED_APPS = [
  ...
  'django.contrib.gis',
]

DATABASES = {
  'default': {
    'ENGINE': 'django.contrib.gis.db.backends.postgis',
      'NAME': '*****',
      'USER': '*****',
      'PASSWORD': '*****',
      'HOST': '*****',
      'PORT': '*****',
  }
}

最後にこちらも確認しておきましょう。

DjangoでLocationを使う

Model

LocationFieldはGISにある緯度経度情報を保有したPoint型をデフォルト値として使用します。

このライブラリの最大の利点は管理画面でマップ確認が出来ることです。

シリアライザーを通して確認してみてください。

from django.contrib.gis.db import models
from django.contrib.gis.geos import Point
from location_field.models.spatial import LocationField

class Shop(models.Model):
  location = LocationField(based_fields=['hoge'], default=Point(40.0, 100.0))

View

こちらは今回もテーマとそこまで関係なくあくまでおまけ要素ですが、PostGISを使用することで位置情報の範囲検索が出来るようになります。

といっても大掛かりな設定は特に必要なく、いつものDjangoのクエリセット抽出に使うfilterメソッドに位置情報のメソッドも加わっているだけです。

例えばhttps://hoge.com/api/search/?latitude=10&longitude=10&radius=5のようなクエリパラメータで検索をかけるようなAPIを想定しているとします。

class ShopViewSet(viewsets.ModelViewSet):
  ...
  def list(self, request):
    latitude = self.request.GET.get('latitude', None)
    longitude = self.request.GET.get('longitude', None)
    radius = self.request.GET.get('radius', None)
    point = Point(longitude, latitude)
    queryset = Shop.objects.filter(location__distance_lte=(point, D(km=radius)))
    ...

これで緯度10、経度10の半径5km以内に該当するShopモデルのクエリセット抽出が出来るようになります。

フィルタの指定方法については公式ドキュメントが丁寧に解説してくれてます。

 

まだ位置情報の扱いについては奥が深そうなので、進めていって気づきなどあればまた共有していきます。