Я работаю над приложением geodjango, в котором я хочу найти все географические местоположения в многоугольнике. Идея заключается в том, что я храню всю географическую информацию (города, страны, POI и т. Д.) В таблице, и если я хочу найти все внутри (много) многоугольника, я запрашиваю базу данных, чтобы найти эти точки.
У меня есть следующие модели:
class Location(models.Model):
name = models.CharField(max_length=250, unique=True)
geometry = models.GeometryField(null=True, blank=True)
class Project(models.Model):
name = models.CharField(max_length=2000, blank=False, null=False, unique=True)
location = models.ManyToManyField(Location, related_name='projects', blank=True)
На мой взгляд, у меня есть:
Класс LocationDetailView (DetailView):
модель = расположение
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
location_geometry = self.get_object().geometry
location_projects = []
if 'Polygon' in location_geometry.geom_type:
# location is a Polygon or MultiPolygon
for loc in Location.objects.prefetch_related('projects').all():
if location_geometry.contains(loc.geometry):
for location_project in loc.projects.all():
location_projects.append({'name': location_project.name, 'pk': location_project.pk})
# Add in a QuerySet of all the projects
context['projects'] = location_projects
return context
Это довольно медленно (и у меня нет только нескольких сотен мест в БД). Как вы можете видеть, я пытался ускорить это путем предварительной загрузки проектов, но когда я смотрю на SQL на панели инструментов отладки, я вижу, что (хотя это быстрый запрос) один запрос дублируется 259 раз:
SELECT
"app_location"."id",
"app_location"."name",
"app_location"."geometry"::bytea,
FROM
"app_location" WHERE "app_location"."id" = 979
Duplicated 259 times.
И этот запрос вызывается один раз, но довольно медленно:
SELECT
("app_project_location"."location_id") AS "_prefetch_related_val_location_id",
"app_project"."id",
"app_project"."name"
FROM
"app_project" INNER JOIN "app_project_location" ON
("app_project"."id" = "app_project_location"."project_id")
WHERE "app_project_location"."location_id" IN (780, ..., 1018, 1019, 1020, 1021, 1022, 1023)
Как бы я мог сделать это более эффективно? Я мог бы, конечно, загрузить все объекты и сделать точку в poly part в python, но я предполагаю, что это можно сделать напрямую в DB?