web-dev-qa-db-ja.com

Djangoでカスタムデータベース関数を作成/使用する方法

プロローグ:

これは、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)
_

次のような既存のデータベース関数に基づいて、独自のカスタムデータベース関数を使用および/または作成する方法はありますか?

Django/GeoDjango ORMでこれらの関数を適用/使用するにはどうすればよいですか?

9
John Moutafis

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()
_
  1. 関数を直接呼び出すには Func() を使用します:

    クエリを機能させるには、次のものも必要です。

    クエリ:

    _MyModel.objects.aggregate(
        pos=Func(F('name'), Value(subst), function='POSITION')
    )
    _
  2. 拡張する独自のデータベース関数を作成する Func

    Funcクラスを拡張して、独自のデータベース関数を作成できます。

    _class Position(Func):
        function = 'POSITION'
    _

    クエリで使用します。

    _MyModel.objects.aggregate(pos=Position('name', Value(subst)))
    _

GeoDjango付録:

GeoDjango では、GIS関連の関数(PostGISTransform関数など)をインポートするために 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')
_
10
John Moutafis