Вопрос

Используя логику расстояния из этот ТАК-пост, я получаю правильно отфильтрованный набор объектов с помощью этого кода:

class LocationManager(models.Manager):
    def nearby_locations(self, latitude, longitude, radius, max_results=100, use_miles=True):
        if use_miles:
            distance_unit = 3959
        else:
            distance_unit = 6371

        from django.db import connection, transaction
        cursor = connection.cursor()

        sql = """SELECT id, (%f * acos( cos( radians(%f) ) * cos( radians( latitude ) ) *
        cos( radians( longitude ) - radians(%f) ) + sin( radians(%f) ) * sin( radians( latitude ) ) ) )
        AS distance FROM locations_location HAVING distance < %d
        ORDER BY distance LIMIT 0 , %d;""" % (distance_unit, latitude, longitude, latitude, int(radius), max_results)
        cursor.execute(sql)
        ids = [row[0] for row in cursor.fetchall()]

        return self.filter(id__in=ids)

Проблема в том, что я не могу понять, как сохранить сортировку списка/набора запросов по значению расстояния.Я не хочу делать это как вызов метода extra() по соображениям производительности (один запрос вместо одного запроса для каждого потенциального местоположения в моей базе данных).Пара вопросов:

  1. Как я могу отсортировать свой список по расстоянию?Даже если убрать встроенную сортировку, которую я определил в своей модели, и использовать «order_by()», она все равно будет сортироваться по чему-то другому (полагаю, по идентификатору).
  2. Я ошибаюсь насчет производительности, и Django оптимизирует запрос, поэтому вместо этого мне следует использовать extra()?
  3. Это совершенно неправильный способ сделать это, и мне следует использовать географическую библиотеку вместо того, чтобы прокручивать это вручную, как дебилизм?
Это было полезно?

Решение

Чтобы ответить на вопросы в обратном порядке:

Касательно 3) Да, вам обязательно следует воспользоваться преимуществами PostGIS и GeoDjango, если вы работаете с геопространственными данными.Просто глупо этого не делать.

Re 2) Я не думаю, что вы могли бы заставить Django выполнить этот запрос за вас, используя .extra() (за исключением принятия этот билет), но он является отличным кандидатом на роль нового метода .raw() в Django 1.2 (см. ниже).

Re 1) Вы получаете список идентификаторов из вашего первого запроса, а затем используете запрос «in», чтобы получить QuerySet объектов, соответствующих этим идентификаторам.Ваш второй запрос не имеет доступа к вычисленному расстоянию из первого запроса;он просто извлекает список идентификаторов (и не имеет значения, в каком порядке вы предоставляете эти идентификаторы).

Возможные решения (если не отказываться от всего этого и использовать GeoDjango):

  1. Обновитесь до бета-версии Django 1.2 и используйте новый метод .raw().Это позволяет Django разумно интерпретировать результаты необработанного SQL-запроса и превращать его в QuerySet реальных объектов модели.Это сократит ваши текущие два запроса в один и сохранит порядок, указанный вами в SQL.Это лучший вариант, если вы можете сделать обновление.

  2. Не беспокойтесь о создании набора запросов Django или объектов модели Django, просто добавьте все необходимые поля в необработанный SQL SELECT, а затем используйте эти строки непосредственно из курсора.Может быть не вариант, если вам позже понадобятся методы модели и т.д.

  3. Выполните третий шаг в коде Python, где вы перебираете набор запросов и создаете список объектов модели Python в том же порядке, что и список идентификаторов, который вы получили в результате первого запроса.Верните этот список вместо QuerySet.Не сработает, если вам нужно выполнить дальнейшую фильтрацию по строке.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top