我有两个Django模型(A和B),它们与任何外键都没有关系,但都有几何字段。
class A(Model):
position = PointField(geography=True)
class B(Model):
position = PointField(geography=True)
我想在空间上将它们联系起来,即给定A的查询集,能够获得B的查询集,其中包含距离A小于给定距离的那些记录。
我还没有找到一种方法使用纯Django的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
有没有人知道更好的方式(更有效)执行这样的查询,或者可能是我的代码失败的原因?
我非常感谢。
我终于设法解决了它,但最后我不得不执行原始的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()]
参考文献: