Как я могу перевести пространственный JOIN на язык запросов Django?
Context
У меня есть две таблицы app_area
и ap_point
, которые никак не связаны (нет Foreign Keys), ожидается, что в каждой есть поле геометрии, соответственно типа polygon
и point
. Голая модель выглядит следующим образом:
from django.contrib.gis.db import models
class Point(models.Model):
# ...
geom = models.PointField(srid=4326)
class Area(models.Model):
# ...
geom = models.PolygonField(srid=4326)
Я хотел бы создать запрос, который отфильтровывает точки, не содержащиеся в полигоне. Если бы мне пришлось писать его с помощью Postgis/SQL, чтобы выполнить эту задачу, я бы выдал такой запрос:
SELECT P.*
FROM
app_area AS A JOIN app_point AS P ON ST_Contains(A.geom, P.geom);
Что просто и эффективно, если определены пространственные индексы.
Моя задача - написать этот запрос без жестко закодированного SQL в моем Django приложении. Поэтому я хотел бы делегировать его ORM, используя классический синтаксис запросов Django.
Выпуск
В любом случае, я не смог найти четкий пример такого запроса в интернете, решения, которые я нашел:
- Либо полагаться на предопределенное отношение, используя
ForeignKeyField
илиprefetch_related
(но это отношение не существует в моем случае); - Или использовать одну геометрию, созданную вручную, для представления полигона (но это не мой случай использования, так как я хочу полагаться на другую таблицу в качестве источника полигонов).
У меня есть ощущение, что это определенно достижимо с Django, но, возможно, я слишком новичок в этом фреймворке, или он недостаточно документирован, или я не нашел подходящего набора ключевых слов, чтобы погуглить его.
Лучшее, что я смог найти в официальной документации - это объект FilteredRelation
, который, кажется, делает то, что я хочу: определяет ON
часть пункта JOIN
, но я не смог настроить правильно, в основном я не понимаю, как заполнить другую таблицу и указать на соответствующие поля.
from django.db.models import F, Q, FilteredRelation
query = Location.objects.annotate(
campus=FilteredRelation(<relation_name>, condition=Q(geom__contains=F("geom")))
)
В основном меня озадачивает поле relation_name
. Я ожидал, что это будет таблица, к которой я присоединюсь (здесь Area
), но похоже, что это имя столбца, которое ожидается.
django.core.exceptions.FieldError: Cannot resolve keyword 'Area' into field. Choices are: created, geom, id, ...
Но этот список полей находится в таблице Point
.
Мой вопрос: Как я могу перевести мой пространственный JOIN
на язык запросов Django?
Nota: Нет необходимости полагаться на объект FilteredRelation
, это просто лучшее соответствие, которое я нашел на данный момент!