Django 提供了Func() https://docs.djangoproject.com/en/1.11/ref/models/expressions/#func-expressions表达式以方便在查询集中调用数据库函数:
Func()
表达式是涉及数据库函数的所有表达式的基本类型,例如COALESCE and LOWER,或像这样的聚合SUM.
关于如何在 Django/GeoDjango ORM 中使用数据库功能,有 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()
-
Use Func() https://docs.djangoproject.com/en/1.11/ref/models/expressions/#func-expressions直接调用该函数:
我们还需要以下内容才能使我们的查询正常工作:
-
聚合 https://docs.djangoproject.com/en/1.11/topics/db/aggregation/为数据库中的每个条目添加一个字段。
-
F() https://docs.djangoproject.com/en/1.11/ref/models/expressions/#f-expressions这使得在模型字段上以及模型字段之间执行算术运算。 https://stackoverflow.com/questions/45593440/how-to-execute-arithmetic-operations-between-model-fields-in-django
-
Value() https://github.com/django/django/blob/master/django/db/models/expressions.py#L620这将清理任何给定值(为什么这很重要?) https://stackoverflow.com/questions/332365/how-does-the-sql-injection-from-the-bobby-tables-xkcd-comic-work?answertab=votes#tab-top
查询:
MyModel.objects.aggregate(
pos=Func(F('name'), Value(subst), function='POSITION')
)
-
创建您自己的数据库功能扩展Func https://docs.djangoproject.com/en/1.11/ref/models/expressions/#func-expressions:
我们可以延长Func
类来创建我们自己的数据库函数:
class Position(Func):
function = 'POSITION'
并在查询中使用它:
MyModel.objects.aggregate(pos=Position('name', Value(subst)))
GeoDjango 附录:
In 地理Django https://docs.djangoproject.com/en/1.11/ref/contrib/gis/,为了导入 GIS 相关函数(例如PostGIS
's Transform
函数)的Func() https://docs.djangoproject.com/en/1.11/ref/models/expressions/#func-expressions方法必须替换为GeoFunc() https://github.com/django/django/blob/master/django/contrib/gis/db/models/functions.py#L88,但本质上是在相同的原则下使用的:
class Transform(GeoFunc):
function='ST_Transform'
还有更复杂的情况GeoFunc
这里出现了用法和一个有趣的用例:如何在 Django 中计算 Frechet 距离? https://stackoverflow.com/questions/56475858/how-to-calculate-frechet-distance-in-django/56483387#56483387
泛化自定义数据库函数附录:
如果您想要创建自定义数据库函数(选项 2)并且希望能够在事先不知道的情况下将其与任何数据库一起使用,您可以使用Func
's 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')