[英]How to make/use a custom database function in 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)
有沒有辦法根據現有的數據庫函數使用和/或創建自己的自定義數據庫函數,如:
Position()
(MySQL) TRIM()
(SQLite) ST_MakePoint()
(PostgreSQL與PostGIS) 如何在Django / GeoDjango ORM中應用/使用這些功能?
Django提供了Func()
表達式,以便於在查詢集中調用數據庫函數:
Func()
表達式是涉及數據庫函數(如COALESCE和LOWER )或聚合(如SUMFunc()
的所有表達式的基本類型。
關於如何在Django / GeoDjango ORM中使用數據庫函數有兩個選項:
為方便起見,我們假設模型名為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中的Frechet距離?
概括自定義數據庫功能附錄:
如果您想要創建自定義數據庫函數(選項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')
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.