Pregunta

Uso de la lógica distancia de este post SO , estoy volviendo un conjunto filtrado adecuadamente de objetos con este código:

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)

El problema es que no puedo encontrar la manera de mantener la lista / queryset ordenados por el valor de la distancia. No quiero hacer esto como un extra llamada al método () por razones de rendimiento (una consulta frente a una consulta en cada ubicación potencial en mi base de datos). Un par de preguntas:

  1. ¿Cómo puedo ordenar mi lista por distancia? Siquiera quitarse la especie nativa he definido en mi modelo y el uso de "order_by ()", sigue siendo la clasificación por alguna otra cosa (id, creo).
  2. ¿Estoy equivocado acerca de la cosa rendimiento y Django optimizar la consulta, por lo que debe utilizar extra () en su lugar?
  3. ¿Es este el camino totalmente equivocado para hacer esto y yo debería usar la biblioteca geo en lugar de esto como un Putz para liar?
¿Fue útil?

Solución

Para responder a sus preguntas en el orden inverso:

Re 3) Sí, definitivamente debe tomar ventaja de PostGIS y GeoDjango si se trabaja con datos geoespaciales. Es una tontería no hacerlo.

Re 2) no creo que usted podría conseguir bastante Django para hacer esta consulta para usted, utilizando .extra () (salvo aceptación de este billete ), pero es un excelente candidato para el método nuevo .raw () en Django 1.2 (véase más adelante).

Re 1) Usted está consiguiendo una lista de identificadores de su primera consulta, y luego usando un "in" consulta para obtener un QuerySet de los objetos correspondientes a los documentos de identidad. Su segunda consulta no tiene acceso a la distancia calculada a partir de la primera consulta; es sólo ir a buscar una lista de identificadores (y no importa el orden que proporcione los ID en, tampoco).

Las posibles soluciones (cortas de zanjas todo esto y utilizando GeoDjango):

  1. Actualizar a Django 1.2 beta y utilizar el método nuevo .raw () . Esto permite Django para interpretar de forma inteligente los resultados de una consulta SQL en bruto y convertirlo en un QuerySet de los objetos de modelo reales. Lo que reduciría sus actuales dos consultas en una sola, y preservar el orden que especifique en SQL. Esta es la mejor opción si usted es capaz de realizar la actualización.

  2. No se moleste en la construcción de un conjunto de consultas Django Django o modelo objetos en absoluto, sólo tiene que añadir todos los campos que necesite en el SQL prima seleccionar y luego usar esas filas directamente desde el cursor. No puede ser una opción si necesita métodos etc modelo más adelante.

  3. Realizar un tercer paso en el código Python, donde iterar sobre el conjunto de consultas y construir una lista de Python de objetos del modelo en el mismo orden en que se enumeran los identificadores de te de regresar de la primera consulta. Devolver esa lista en lugar de un QuerySet. no funcionará si lo que necesita hacer aún más el filtrado de la línea.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top