Я работаю над проектом Django, который требует, чтобы я сообщал через веб-службу для каждого элемента в школьной таблице все больницы, которые случайно оказались на заданном расстоянии. Вот фиктивная реализация двух моделей:
class School(models.Model):
location = models.PointField(srid=4326, geography=True)
...some other fields...
objects = models.GeoManager()
class Hospital
location = models.PointField(srid=4326, geography=True)
...some other fields...
objects = models.GeoManager()
Я заявлю для протокола, что это надуманный пример, но суть остается в том, что:
- Ни одна из моделей не имеет отношений внешнего ключа с другой (и не должна)
- Единственные отношения через расстояние
Теперь я использую Django Rest Framework (DRF) для обработки своих запросов, и я использую классы Serializer, которые он предоставляет, чтобы сделать что-то в этом роде:
class SchoolSerializer(serializers.ModelSerializer):
nearby_hospitals = serializers.SerializerMethodField('get_nearby_hospitals')
class Meta:
model = School
fields = ('location', 'nearby_hospitals',)
def get_nearby_hospitals(self, obj):
geom = obj.location
try:
locations = Hospitals.objects.filter(loc__dwithin=(geom, 10000))
return HospitalSerializer(locations, many=True).data
except:
return
Это работает, но не эффективно. По сути, DRF загружает все школы, а затем перебирает каждую школу и выполняет запрос в get_nearby_hospitals. Количество запросов к базе данных равно количеству предметов в школах плюс один (чтобы получить школы).
В идеале я бы хотел, чтобы решение Django выполняло что-то в этом духе (очевидно, с перечисленными полями, псевдонимами для конфликтующих имен столбцов идентификаторов и т. д.):
SELECT * FROM schools JOIN
hospitals ON ST_DWithin(schools.location, hospitals.location, 10000)
Приведенный выше запрос выдает пересечение всех школ и больниц на нужном расстоянии. Я мог бы вручную объединить эти результаты с набором запросов School.objects.all()
или написать лучший запрос и вызвать метод raw
QuerySet, чтобы получить то, что мне нужно, одним выстрелом.
Есть ли лучшее или более «Django Way» решение этой проблемы?