Django 정렬 계산 된 필드 별
문제
거리 논리를 사용합니다 이렇게 게시됩니다, 나는이 코드를 사용하여 적절하게 여겨지는 객체 세트를 돌려 받고 있습니다.
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)
문제는 목록/ 쿼리 세트를 거리 값으로 정렬하는 방법을 알 수 없다는 것입니다. 성능 이유를 위해 추가 () 메소드 호출 로이 작업을 수행하고 싶지 않습니다 (데이터베이스의 각 잠재적 위치에 대한 하나의 쿼리 대 한 쿼리). 몇 가지 질문 :
- 내 목록을 멀리서 어떻게 정렬 할 수 있습니까? 내 모델에서 정의한 기본 정렬을 제거하고 "order_by ()"를 사용하더라도 여전히 다른 것에 의해 분류되고 있습니다 (ID, I Believe).
- 성능에 대해 잘못되었고 Django는 쿼리를 최적화하므로 대신 extra ()를 사용해야합니까?
- 이것이 완전히 잘못된 방법입니까? 나는 Putz처럼 이것을 핸드 롤링하는 대신 Geo 라이브러리를 사용해야합니까?
해결책
귀하의 질문을 역순으로 받으려면 :
RE 3) 예, 지리 공간 데이터를 사용하는 경우 Postgis와 Geodjango를 반드시 활용해야합니다. 그것은 단지 어리석지 않습니다.
re 2) .extra ()를 사용하여 Django 가이 쿼리를 할 수 있다고 생각하지 않습니다. 이 티켓), 그러나 Django 1.2의 새로운 .raw () 메소드의 훌륭한 후보입니다 (아래 참조).
Re 1) 첫 번째 쿼리에서 ID 목록을 얻은 다음 "in"쿼리를 사용하여 해당 ID에 해당하는 객체의 쿼리 세트를 가져옵니다. 두 번째 쿼리는 첫 번째 쿼리에서 계산 된 거리에 액세스 할 수 없습니다. 그것은 단지 ID 목록을 가져 오는 것입니다 (그리고 해당 ID를 제공하는 순서도 신경 쓰지 않습니다).
가능한 솔루션 (이 모든 것을 버리고 Geodjango를 사용하지 않음) :
Django 1.2 베타로 업그레이드하고 사용하십시오 새로운 .raw () 메소드. 이를 통해 Django는 원시 SQL 쿼리의 결과를 지능적으로 해석하고 실제 모델 객체의 쿼리 세트로 전환 할 수 있습니다. 현재 두 쿼리를 하나로 줄이고 SQL로 지정된 순서를 보존합니다. 업그레이드를 할 수있는 최선의 옵션입니다.
Django Queryset 또는 Django 모델 객체를 전혀 구조화하지 마십시오. 필요한 모든 필드를 RAW SQL SELECT에 추가 한 다음 커서에서 직접 해당 행을 사용하십시오. 나중에 모델 방법 등이 필요한 경우 옵션이 아닐 수도 있습니다.
Python Code에서 세 번째 단계를 수행하여 쿼리 세트를 반복하고 첫 번째 쿼리에서 돌아온 IDS 목록과 동일한 순서로 Python 목록을 구성합니다. 쿼리 세트 대신 해당 목록을 반환하십시오. 라인을 더 이상 필터링 해야하는 경우 작동하지 않습니다.