数据库
首页 > 数据库> > 如何在Django中创建/使用自定义数据库函数

如何在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