Pergunta

Usando a lógica de distância de isso é tão post, Estou recebendo um conjunto de objetos corretamente filtrados com 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)

O problema é que não consigo descobrir como manter a lista/ conjunto de consultas classificadas pelo valor da distância. Não quero fazer isso como um método extra () que exige motivos de desempenho (uma consulta versus uma consulta em cada local potencial no meu banco de dados). Algumas perguntas:

  1. Como posso classificar minha lista por distância? Mesmo tirando o tipo nativo que defini no meu modelo e usando "order_by ()", ainda está classificando por outra coisa (eu acredito).
  2. Estou errado sobre a coisa do desempenho e o Django otimizará a consulta, então devo usar extra ()?
  3. Essa é a maneira totalmente errada de fazer isso e eu deveria usar a biblioteca geográfica em vez de rolar a mão como um putz?
Foi útil?

Solução

Para fazer suas perguntas em ordem inversa:

Re 3) Sim, você definitivamente deve aproveitar o PostGIS e o Geodjango se estiver trabalhando com dados geoespaciais. É apenas bobo não fazê -lo.

Re 2) Eu não acho que você poderia fazer com que Django faça esta consulta para você usar .extra () (exceto a aceitação de Este ingresso), mas é um excelente candidato ao novo método .raw () no Django 1.2 (veja abaixo).

Re 1) Você está obtendo uma lista de IDs da sua primeira consulta e, em seguida, usando uma consulta "In" para obter uma consulta dos objetos correspondentes a esses IDs. Sua segunda consulta não tem acesso à distância calculada da primeira consulta; Está apenas buscando uma lista de IDs (e também não se importa com a ordem em que você fornece esses IDs).

Possíveis soluções (com falta de abandonar tudo isso e usar geodjango):

  1. Atualize para Django 1.2 beta e use o Método .raw (). Isso permite que o Django interprete de maneira inteligente os resultados de uma consulta SQL bruta e transformá -la em um conjunto de objetos de modelo reais. O que reduziria suas duas consultas atuais em uma e preservaria a ordem que você especificará no SQL. Esta é a melhor opção se você puder fazer a atualização.

  2. Não se preocupe em construir uma consulta Django ou objetos de modelo Django, basta adicionar todos os campos necessários à seleção SQL bruta e, em seguida, usar essas linhas diretas do cursor. Pode não ser uma opção se você precisar de métodos de modelo etc. posteriormente.

  3. Execute uma terceira etapa no código Python, onde você itera sobre o conjunto de consultas e constrói uma lista Python de objetos de modelo na mesma ordem que a lista IDS que você recebeu da primeira consulta. Retorne essa lista em vez de uma consulta. Não funcionará se você precisar fazer mais filtragem na linha.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top