GeoDjango データベース API

空間バックエンド (Spatial Backend)

GeoDjango は現在、次の空間データベースバックエンドを提供しています:

  • django.contrib.gis.db.backends.postgis
  • django.contrib.gis.db.backends.mysql
  • django.contrib.gis.db.backends.oracle
  • django.contrib.gis.db.backends.spatialite

MySQL の空間データに関する制限

Django は、最近の MySQL バージョンで利用可能な、実際のジオメトリを操作する空間関数をサポートしています。しかし、空間関数は PostGIS のような他のバックエンドほど豊富ではありません。

ラスターのサポート

RasterField は現在、PostGIS バックエンドのみに実装されています。ラスターフィールドに対する空間ルックアップは可能ですが、空間データベース関数や集計は実装されていません。

モデルを作成し、ジオメトリフィールドを保存する

以下にジオメトリオブジェクトの作成例を示します (Zipcode モデルを想定):

>>> from zipcode.models import Zipcode
>>> z = Zipcode(code=77096, poly="POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")
>>> z.save()

GEOSGeometry オブジェクトもジオメトリモデルを保存するために使用できます:

>>> from django.contrib.gis.geos import GEOSGeometry
>>> poly = GEOSGeometry("POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))")
>>> z = Zipcode(code=77096, poly=poly)
>>> z.save()

さらに、GEOSGeometry がフィールドの座標系と異なる座標系 (異なる SRID 値を持つ) 場合は、空間データベースの変換プロシージャを使用して、モデルのフィールドの SRID に暗黙的に変換されます:

>>> poly_3084 = GEOSGeometry(
...     "POLYGON(( 10 10, 10 20, 20 20, 20 15, 10 10))", srid=3084
... )  # SRID 3084 is 'NAD83(HARN) / Texas Centric Lambert Conformal'
>>> z = Zipcode(code=78212, poly=poly_3084)
>>> z.save()
>>> from django.db import connection
>>> print(
...     connection.queries[-1]["sql"]
... )  # printing the last SQL statement executed (requires DEBUG=True)
INSERT INTO "geoapp_zipcode" ("code", "poly") VALUES (78212, ST_Transform(ST_GeomFromWKB('\\001 ... ', 3084), 4326))

そのため、ジオメトリパラメータは GEOSGeometry オブジェクト、WKT (Well Known Text [1]) 、HEXEWKB (PostGIS 固有のジオメトリで、16 進数の WKB ジオメトリ [2]) 、GeoJSON (RFC 7946 参照) を使用して渡すことができます。基本的に、入力が GEOSGeometry オブジェクトでない場合、ジオメトリフィールドは入力から GEOSGeometry インスタンスを作成しようとします。

GEOSGeometry オブジェクトを作成する詳細については、GEOS チュートリアル を参照してください。

ラスターフィールドを持つモデルの作成と保存

ラスターモデルを作成するとき、ラスターフィールドは、遅延評価を使用して、入力を GDALRaster に暗黙的に変換します。そのため、ラスタフィールドは GDALRaster コンストラクタが受け付けるすべての入力を受け入れます。

以下は、ラスターファイル volcano.tif からラスターオブジェクトを作成する方法の例です (Elevation モデルを想定) :

>>> from elevation.models import Elevation
>>> dem = Elevation(name="Volcano", rast="/path/to/raster/volcano.tif")
>>> dem.save()

GDALRaster オブジェクトもラスターモデルの保存に使用できます:

>>> from django.contrib.gis.gdal import GDALRaster
>>> rast = GDALRaster(
...     {
...         "width": 10,
...         "height": 10,
...         "name": "Canyon",
...         "srid": 4326,
...         "scale": [0.1, -0.1],
...         "bands": [{"data": range(100)}],
...     }
... )
>>> dem = Elevation(name="Canyon", rast=rast)
>>> dem.save()

これは次と等価です:

>>> dem = Elevation.objects.create(
...     name="Canyon",
...     rast={
...         "width": 10,
...         "height": 10,
...         "name": "Canyon",
...         "srid": 4326,
...         "scale": [0.1, -0.1],
...         "bands": [{"data": range(100)}],
...     },
... )

空間のルックアップ (Spatial Lookup)

GeoDjango のルックアップ型は filter()exclude() などの manager メソッドで使うことができます。しかし、 GeoDjango 固有のルックアップ型は空間フィールドでのみ利用可能です。

「通常の」フィールド (例えば CharField) のフィルタは、地理情報フィールドのフィルタと連結すできます。ジオメトリルックアップはジオメトリとラスタの両方の入力を受け付けます。

地理情報ルックアップの一般的な構造を以下に記載します。完全なリファレンスは、 空間ルックアップのリファレンス にあります。

ジオメトリ・ルックアップ

地理情報クエリにおいて、ジオメトリを用いる一般的な形式は以下の通りです (GeoDjango モデル API で使用されている Zipcode モデルを想定):

>>> qs = Zipcode.objects.filter(<field>__<lookup_type>=<parameter>)
>>> qs = Zipcode.objects.exclude(...)

例:

>>> qs = Zipcode.objects.filter(poly__contains=pnt)
>>> qs = Elevation.objects.filter(poly__contains=rst)

この場合、 poly は地理情報フィールド、 contains は空間ルックアップタイプ、 pnt はパラメータ (GEOSGeometry オブジェクト、または GeoJSON、WKT、HEXEWKB の文字列)、そして rstGDALRaster オブジェクトです。

ラスター・ルックアップ

ラスタールックアップの構文はジオメトリの構文に似ています。唯一の違いは、バンドインデックスを追加入力として指定できることです。バンドインデックスが指定されていない場合は、デフォルトで最初のバンドが使用されます (インデックス"0") 。その場合、構文はジオメトリルックアップの構文と同一です。

バンドインデックスを指定するには、ルックアップに追加のパラメータを両側で指定できます。左側では、バンドインデックスを渡すためにダブルアンダースコア構文が使用されます。右側では、ラスターとバンドのインデックスのタプルを指定できます。

これにより、ラスターを使用するルックアップの一般的な形式が得られます (GeoDjango モデル API で使用されている Elevation モデルを想定):

>>> qs = Elevation.objects.filter(<field>__<lookup_type>=<parameter>)
>>> qs = Elevation.objects.filter(<field>__<band_index>__<lookup_type>=<parameter>)
>>> qs = Elevation.objects.filter(<field>__<lookup_type>=(<raster_input, <band_index>)

例:

>>> qs = Elevation.objects.filter(rast__contains=geom)
>>> qs = Elevation.objects.filter(rast__contains=rst)
>>> qs = Elevation.objects.filter(rast__1__contains=geom)
>>> qs = Elevation.objects.filter(rast__contains=(rst, 1))
>>> qs = Elevation.objects.filter(rast__1__contains=(rst, 1))

例の左辺では、 rast が地理情報ラスタフィールドで、 contains が空間ルックアップタイプです。右辺の geom はジオメトリ入力で、 rstGDALRaster オブジェクトです。バンドインデックスは最初の2つのクエリではデフォルトで 0 に設定され、他のクエリでは 1 に設定されます。

すべての空間ルックアップはラスターオブジェクトの両側で使用できますが、すべての基本演算子がラスター入力をネイティブに受け付けるわけではありません。演算子がジオメトリ入力を想定している場合、ラスタは自動的にジオメトリに変換されます。ルックアップ結果を解釈する際には、この点に留意することが重要です。

ラスターをサポートするタイプは 互換表 のすべてのルックアップにリストされています。ラスタを含むルックアップは現在のところ PostGIS バックエンドでのみ利用可能です。

距離クエリ

はじめに

残念ながら、地球は平らではないため、空間データでの距離計算は厄介です。PostGIS の制限により、地理座標系のフィールドを使用した距離のクエリは、別の方法で表現しなければならない場合があります。詳細は GeoDjango モデル API ドキュメントの SRID の選択 セクションを参照してください。

距離ルックアップ

利用可能なDB: PostGIS、MariaDB、MySQL、Oracle、SpatiaLite、PGRaster (ネイティブ)

以下の距離ルックアップが利用できます:

注釈

距離をクエリするのではなく、 計測 する場合は Distance 関数を使います。

距離ルックアップは、次のように構成されるタプルパラメータを受け取ります:

  1. 計算のベースとなるジオメトリまたはラスター。
  2. 距離を含む数字または Distance オブジェクト。

Distance オブジェクトが使用されている場合、任意の単位で表現される可能性があります(SQL 生成時には、フィールドの単位に変換された単位が使用される)。それ以外の場合、数値パラメータはフィールドの単位であると想定されます。

注釈

PostGIS では、ST_Distance_Sphere は、地理距離クエリを実行するジオメトリタイプを制限しません。 [3] ただし、これらのクエリには、 全て の行のたびに大圏距離を動的に計算する必要があるため、長い時間がかかる可能性があります。これは従来のジオメトリフィールドに空間インデックスが使用できないためです。

WGS84 の距離クエリでより良いパフォーマンスを得るには、代わりにデータベースで ジオグラフィカラム を使うことを検討してください。フィールド定義で geography=True と設定することで、 GeoDjango にジオグラフィカラムを使うように指示できます。

例えば、SouthTexasCity というモデル (GeoDjango 距離テスト から) が、テキサス州南部の都市に有効な 投影 座標系にあるとします:

from django.contrib.gis.db import models


class SouthTexasCity(models.Model):
    name = models.CharField(max_length=30)
    # A projected coordinate system (only valid for South Texas!)
    # is used, units are in meters.
    point = models.PointField(srid=32140)

距離クエリは次のように実行できます:

>>> from django.contrib.gis.geos import GEOSGeometry
>>> from django.contrib.gis.measure import D  # ``D`` is a shortcut for ``Distance``
>>> from geoapp.models import SouthTexasCity
# Distances will be calculated from this point, which does not have to be projected.
>>> pnt = GEOSGeometry("POINT(-96.876369 29.905320)", srid=4326)
# If numeric parameter, units of field (meters in this case) are assumed.
>>> qs = SouthTexasCity.objects.filter(point__distance_lte=(pnt, 7000))
# Find all Cities within 7 km, > 20 miles away, and > 100 chains away (an obscure unit)
>>> qs = SouthTexasCity.objects.filter(point__distance_lte=(pnt, D(km=7)))
>>> qs = SouthTexasCity.objects.filter(point__distance_gte=(pnt, D(mi=20)))
>>> qs = SouthTexasCity.objects.filter(point__distance_gte=(pnt, D(chain=100)))

ラスタークエリは、ジオメトリフィールド "point" をラスターフィールドに置き換えるか、"pnt" オブジェクトをラスターオブジェクトに置き換えるか、またはその両方で同じように機能します。右辺のラスター入力のバンドインデックスを指定するには、3値のタプルをルックアップに渡すことができます:

>>> qs = SouthTexasCity.objects.filter(point__distance_gte=(rst, 2, D(km=7)))

ラスター rst のバンドのうち、インデックス2 (3番目のバンド) がルックアップに使用されます。

互換表

空間のルックアップ (Spatial Lookup)

以下の表は、各空間データベースバックエンドで利用可能な空間ルックアップの概要です。PostGIS Raster (PGRaster) のルックアップは ラスタールックアップの詳細 に記載されている3つのカテゴリに分類されます: ネイティブサポート N、双方向ネイティブサポート B、ジオメトリ変換サポート C

ルックアップタイプ PostGIS Oracle MariaDB MySQL [4] SpatiaLite PGRaster
bbcontains X   X X X N
bboverlaps X   X X X N
contained X   X X X N
contains X X X X X B
contains_properly X         B
coveredby X X     X B
covers X X     X B
crosses X   X X X C
disjoint X X X X X B
distance_gt X X X X X N
distance_gte X X X X X N
distance_lt X X X X X N
distance_lte X X X X X N
dwithin X X     X B
equals X X X X X C
exact X X X X X B
intersects X X X X X B
isempty X          
isvalid X X   X X  
overlaps X X X X X B
relate X X X   X C
same_as X X X X X B
touches X X X X X B
within X X X X X B
left X         C
right X         C
overlaps_left X         B
overlaps_right X         B
overlaps_above X         C
overlaps_below X         C
strictly_above X         C
strictly_below X         C

データベース関数

次の表は、各空間バックエンドで使用できるジオグラフィ固有のデータベース関数の概要です。

関数 PostGIS Oracle MariaDB MySQL SpatiaLite
Area X X X X X
AsGeoJSON X X X X X
AsGML X X     X
AsKML X       X
AsSVG X       X
AsWKB X X X X X
AsWKT X X X X X
Azimuth X       X (LWGEOM/RTTOPO)
BoundingCircle X X     X (≥ 5.1)
Centroid X X X X X
ClosestPoint X       X
Difference X X X X X
Distance X X X X X
Envelope X X X X X
ForcePolygonCW X       X
FromWKB X X X X X
FromWKT X X X X X
GeoHash X     X X (LWGEOM/RTTOPO)
Intersection X X X X X
IsEmpty X        
IsValid X X   X X
Length X X X X X
LineLocatePoint X       X
MakeValid X       X (LWGEOM/RTTOPO)
MemSize X        
NumGeometries X X X X X
NumPoints X X X X X
Perimeter X X     X
PointOnSurface X X X   X
Reverse X X     X
Scale X       X
SnapToGrid X       X
SymDifference X X X X X
Transform X X     X
Translate X       X
Union X X X X X

集計関数

The following table provides a summary of what GIS-specific aggregate functions are available on each spatial backend. Please note that MariaDB does not support any of these aggregates, and is thus excluded from the table.

集計関数 PostGIS Oracle MySQL SpatiaLite
Collect X   X (≥ 8.0.24) X
Extent X X   X
Extent3D X      
MakeLine X     X
Union X X   X

脚注

[1]参照 Open Geospatial Consortium, Inc. の OpenGIS Simple Feature Specification For SQL 、ドキュメント 99-049 (May 5, 1999), at Ch. 3.2.5, p. 3-11 (SQL Textual Representation of Geometry) 。
[2]参照 PostGIS EWKB, EWKT and Canonical Forms, PostGIS documentation at Ch. 4.1.2.
[3]参照 PostGIS documentationST_DistanceSphere を参照してください。
[4]詳細は MySQL の空間データに関する制限 セクションを参照してください。
Back to Top