при условии, что функция, которую вы хотите использовать, существует в каждой базе данных

г:

Этот вопрос часто возникает в SO:

Эквивалент PostGIS ST_MakeValid в Django GEOSГеоджанго: как буферизовать из точкиПолучить случайную точку от Джанго PolygonFieldДжанго кастом для сложной функции (функция sql)

и может быть применено к вышеуказанному, а также к следующему:

Django F выражение на объектах datetime

Я хотел написать пример документации SO, но так как он был закрыт 8 августа 2017 года, я последую предложениюэтот широко обсуждаемый и обсуждаемый мета-ответ и напишите мой пример в качестве поста с автоответчиком.

Конечно, я был бы более чем рад увидеть и другой подход !!

Вопрос:

Django / GeoDjango имеет некоторые функции базы данных, такие какLower() или жеMakeValid() который можно использовать так:

Author.objects.create(name='Margaret Smith')
author = Author.objects.annotate(name_lower=Lower('name')).get()
print(author.name_lower)

Есть ли способ использовать и / или создать свою собственную функцию базы данных на основе существующих функций базы данных, таких как:

Position() (Баз данных)TRIM() (SQLite)ST_MakePoint() (PostgreSQL с PostGIS)

Как я могу применить / использовать эти функции в Django / GeoDjango ORM?

Ответы на вопрос(1)

Решение Вопроса

Func() выражение для облегчения вызова функций базы данных в наборе запросов:

Func() выражения являются базовым типом всех выражений, которые включают функции базы данных, такие какCOALESCE а такжеНИЖНИЙили агрегаты, такие как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()чтобы вызвать функцию напрямую:

Нам также потребуется следующее, чтобы наши запросы работали:

агрегирование добавить поле к каждой записи в нашей базе данных.F() который позволяетвыполнение арифметических операций над и между полями модели.Value() который будет дезинфицировать любое заданное значение (почему это важно?)

Запрос:

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() метод get замененGeoFunc() и используется точно так же.

Обобщить пользовательскую функцию базы данных Приложение:

В случае, если вы хотите создать пользовательскую функцию базы данных (вариант 2) и хотите иметь возможность использовать ее с любой базой данных, не зная об этом заранее, вы можете использоватьFunc«sas_<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')

Ваш ответ на вопрос