プロローグ:
これは、SOで頻繁に発生する質問です。
上記および以下に適用できます。
SOドキュメントで例を作成したかったのですが、2017年8月8日にシャットダウンされたので、 これは広く支持され議論されているメタ回答 の提案に従います。私の例を自己回答の投稿として書いてください。
もちろん、別のアプローチも見られたら嬉しいです!!
質問:
Django/GeoDjangoには、 Lower()
または MakeValid()
のようなデータベース関数があり、次のように使用できます。
_Author.objects.create(name='Margaret Smith')
author = Author.objects.annotate(name_lower=Lower('name')).get()
print(author.name_lower)
_
次のような既存のデータベース関数に基づいて、独自のカスタムデータベース関数を使用および/または作成する方法はありますか?
Position()
(MySQL)TRIM()
(SQLite)ST_MakePoint()
(PostGISを使用したPostgreSQL)Django/GeoDjango ORMでこれらの関数を適用/使用するにはどうすればよいですか?
Djangoは、クエリセット内のデータベース関数の呼び出しを容易にするために Func()
式を提供します。
Func()
式は、[〜#〜] coalesce [〜#〜]やなどのデータベース関数を含むすべての式の基本型です。 [〜#〜] lower [〜#〜]、または[〜#〜] sum [〜 #〜]。
Django/GeoDjangoORMでデータベース関数を使用する方法には2つのオプションがあります。
便宜上、モデルの名前はMyModel
であり、部分文字列はsubst
:という名前の変数に格納されていると仮定します。
_from Django.contrib.gis.db import models as gis_models
class MyModel(models.Model):
name = models.CharField()
the_geom = gis_models.PolygonField()
_
関数を直接呼び出すには Func()
を使用します:
クエリを機能させるには、次のものも必要です。
F()
これにより モデルフィールド上およびモデルフィールド間の算術演算の実行Value()
これは任意の値をサニタイズします( なぜこれが重要なのですか?)クエリ:
_MyModel.objects.aggregate(
pos=Func(F('name'), Value(subst), function='POSITION')
)
_
拡張する独自のデータベース関数を作成する Func
:
Func
クラスを拡張して、独自のデータベース関数を作成できます。
_class Position(Func):
function = 'POSITION'
_
クエリで使用します。
_MyModel.objects.aggregate(pos=Position('name', Value(subst)))
_
GeoDjango付録:
GeoDjango では、GIS関連の関数(PostGIS
のTransform
関数など)をインポートするために Func()
メソッド GeoFunc()
に置き換える必要がありますが、基本的に同じ原則で使用されます。
_class Transform(GeoFunc):
function='ST_Transform'
_
GeoFunc
の使用法にはもっと複雑なケースがあり、興味深いユースケースがここに現れています: Djangoでフレシェ距離を計算する方法は?
カスタムデータベース関数の一般化付録:
カスタムデータベース関数(オプション2)を作成し、それを事前に知らなくても任意のデータベースで使用できるようにしたい場合は、Func
の_as_<database-name>
_メソッドを使用できます使用したい関数がすべてのデータベースに存在する場合:
_class Position(Func):
function = 'POSITION' # MySQL method
def as_sqlite(self, compiler, connection):
#SQLite method
return self.as_sql(compiler, connection, function='INSTR')
def as_postgresql(self, compiler, connection):
# PostgreSQL method
return self.as_sql(compiler, connection, function='STRPOS')
_