如何在Django中创建/使用自定义数据库函数
作者:互联网
序幕:
这是SO中经常出现的问题:
> Equivalent of PostGIS ST_MakeValid in Django GEOS
> Geodjango: How to Buffer From Point
> Get random point from django PolygonField
> Django custom for complex Func (sql function)
并且可以应用于上述以及以下内容:
> Django F expression on datetime objects
我想在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 with PostGIS)
如何在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中使用数据库函数有两个选项:
为方便起见,我们假设模型名为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()
直接调用该函数:
我们还需要以下内容才能使我们的查询工作:
> 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中,为了导入与GIS相关的功能(如PostGIS的Transform功能),Func()
方法必须由GeoFunc()
替换,但它基本上按照相同的原则使用:
class Transform(GeoFunc):
function='ST_Transform'
有更复杂的GeoFunc使用案例,这里出现了一个有趣的用例:How to calculate Frechet Distance in 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')
标签:geodjango,python,django,database 来源: https://codeday.me/bug/20191001/1837866.html