序言:
这是 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)
并且可以应用于以上以及以下:
我想在 SO 文档上写一个例子,但由于它在 2017 年 8 月 8 日被关闭,我将听从 this widely upvoted and discussed meta answer 的建议,并将我的例子写成一个 self 回答的帖子。
当然,我也很乐意看到任何不同的方法!!
问题:
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()
(带有 PostGIS 的 PostgreSQL)
如何在 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
的变量中:
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')
关于python - 如何在 Django 中创建/使用自定义数据库函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46689979/