如何 make/use 在 Django 中自定义数据库函数
How to make/use a custom database function in Django
序言:
这是SO中经常出现的问题:
- Geodjango: How to Buffer From Point
并且可以应用于以上以及以下:
我想在 SO 文档上编写一个示例,但自从它于 2017 年 8 月 8 日关闭以来,我将遵循 this widely upvoted and discussed meta answer 的建议并将我的示例编写为自我回答 post.
当然,我也很乐意看到任何不同的方法!!
问题:
Django/GeoDjango 有一些像 Lower()
or MakeValid()
这样的数据库函数,可以这样使用:
Author.objects.create(name='Margaret Smith')
author = Author.objects.annotate(name_lower=Lower('name')).get()
print(author.name_lower)
有什么方法可以使用 and/or 根据现有的数据库函数创建我自己的自定义数据库函数,例如:
Position()
(MySQL)
TRIM()
(SQLite)
ST_MakePoint()
(带有 PostGIS 的 PostgreSQL)
如何apply/use Django/GeoDjango ORM 中的那些函数?
Django 提供了 Func()
表达式来方便在查询集中调用数据库函数:
Func()
expressions are the base type of all expressions that involve database functions like COALESCE and LOWER, or aggregates like SUM.
关于如何在 Django/GeoDjango ORM 中使用数据库函数有 2 个选项:
为方便起见,我们假设模型名为 MyModel
并且子字符串存储在名为 subst
:[=41 的变量中=]
from django.contrib.gis.db import models as gis_models
class MyModel(models.Model):
name = models.CharField()
the_geom = gis_models.PolygonField()
使用Func()
直接调用函数:
我们还需要以下内容才能使我们的查询正常工作:
- Aggregation 为我们数据库中的每个条目添加一个字段。
F()
which allows
Value()
which will sanitize any given value (why is this important?)
查询:
MyModel.objects.aggregate(
pos=Func(F('name'), Value(subst), function='POSITION')
)
创建自己的数据库函数扩展 Func
:
我们可以扩展 Func
class 来创建我们自己的数据库函数:
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
用法案例,这里出现了一个有趣的用例:
泛化自定义数据库函数附录:
如果您想创建一个自定义数据库函数(选项 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')
序言:
这是SO中经常出现的问题:
- Geodjango: How to Buffer From Point
并且可以应用于以上以及以下:
我想在 SO 文档上编写一个示例,但自从它于 2017 年 8 月 8 日关闭以来,我将遵循 this widely upvoted and discussed meta answer 的建议并将我的示例编写为自我回答 post.
当然,我也很乐意看到任何不同的方法!!
问题:
Django/GeoDjango 有一些像 Lower()
or MakeValid()
这样的数据库函数,可以这样使用:
Author.objects.create(name='Margaret Smith')
author = Author.objects.annotate(name_lower=Lower('name')).get()
print(author.name_lower)
有什么方法可以使用 and/or 根据现有的数据库函数创建我自己的自定义数据库函数,例如:
Position()
(MySQL)TRIM()
(SQLite)ST_MakePoint()
(带有 PostGIS 的 PostgreSQL)
如何apply/use Django/GeoDjango ORM 中的那些函数?
Django 提供了 Func()
表达式来方便在查询集中调用数据库函数:
Func()
expressions are the base type of all expressions that involve database functions like COALESCE and LOWER, or aggregates like SUM.
关于如何在 Django/GeoDjango ORM 中使用数据库函数有 2 个选项:
为方便起见,我们假设模型名为 MyModel
并且子字符串存储在名为 subst
:[=41 的变量中=]
from django.contrib.gis.db import models as gis_models
class MyModel(models.Model):
name = models.CharField()
the_geom = gis_models.PolygonField()
使用
Func()
直接调用函数:我们还需要以下内容才能使我们的查询正常工作:
- Aggregation 为我们数据库中的每个条目添加一个字段。
F()
which allowsValue()
which will sanitize any given value (why is this important?)
查询:
MyModel.objects.aggregate( pos=Func(F('name'), Value(subst), function='POSITION') )
创建自己的数据库函数扩展
Func
:我们可以扩展
Func
class 来创建我们自己的数据库函数: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
用法案例,这里出现了一个有趣的用例:
泛化自定义数据库函数附录:
如果您想创建一个自定义数据库函数(选项 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')