GeoDjango: Как выполнить запрос пространственно близких записей - PullRequest
0 голосов
/ 20 апреля 2019

У меня есть две модели Django (A и B), которые не связаны каким-либо внешним ключом, но обе имеют геометрическое поле.

class A(Model):
    position = PointField(geography=True)

class B(Model):
    position = PointField(geography=True)

Я хотел бы связать их пространственно, т. Е. Учитывая набор запросов A, чтобы иметь возможность получить набор запросов B, содержащий те записи, которые находятся на расстоянии менее заданного расстояния до A.

Я не нашел способа использовать ORM чистого Джанго для такой вещи.

Конечно, я мог бы написать свойство в A, например:

@property
def nearby(self):
    return B.objects.filter(position__dwithin=(self.position, 0.1))

Но это позволяет мне выбирать соседние записи в каждом экземпляре, а не в одном запросе, что далеко от эффективности.

Я также пытался сделать это:

nearby = B.objects.filter(position__dwithin=(OuterRef('position'), 0.1))
query = A.objects.annotate(nearby=Subquery(nearby.values('pk')))

list(query)  # error here

Однако я получаю эту ошибку для последней строки:

ValueError: This queryset contains a reference to an outer query and may only be used in a subquery

Кто-нибудь знает лучший (более эффективный) способ выполнения такого запроса или, возможно, причину сбоя моего кода?

Я очень ценю.

1 Ответ

1 голос
/ 21 апреля 2019

Мне наконец удалось решить эту проблему, но мне пришлось выполнить необработанный SQL-запрос в конце.

Это вернет все записи A с аннотацией, включая список всех близлежащих записей B:

from collections import namedtuple

from django.db import connection


with connection.cursor() as cursor:
    cursor.execute('''SELECT id, array_agg(b.id) as nearby FROM myapp_a a
                      LEFT JOIN myapp_b b ON ST_DWithin(a.position, p.position, 0.1)
                      GROUP BY a.id''')

    nt_result = namedtuple('Result', [col[0] for col in cursor.description])
    results = [nt_result(*row) for row in cursor.fetchall()]

Ссылки:

...