Как я могу перевести пространственный 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, это просто лучшее соответствие, которое я нашел на данный момент!

Вернуться на верх