序幕:
这是SO中经常出现的问题:
并且可以应用于上述以及以下内容:
我想在SO文档上撰写一个例子,但自2017年8月8日关闭以来,我将遵循this widely upvoted and discussed meta answer的建议并将我的例子写成一个自我回答的帖子。
当然,我也很乐意看到任何不同的方法!
题:
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)或聚合(如SUM)的所有表达式的基本类型。
关于如何在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()
to直接调用该函数:
我们还需要以下内容才能使我们的查询工作:
Aggregation为我们数据库中的每个条目添加一个字段。
F()
允许the execution of arithmetic operations on and between model fields.
Value()
将消毒任何给定的价值(why is this important?)
查询:
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中,Func()
方法被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')