문제

Django의 기본 상점 위치에 대한 근접 검색을 처리하려고합니다. Geodjango의 거리 필터를 사용할 수 있도록 앱을 사용하여 Postgis를 운반하는 대신 모델 쿼리에서 Cosines 거리 공식의 구형 법칙을 사용하고 싶습니다. 효율성을 위해 모든 계산을 하나의 쿼리의 데이터베이스에서 수행하고 싶습니다.

인터넷의 MySQL 쿼리 예는 다음과 같은 코사인의 구형 법칙을 구현합니다.

SELECT id, ( 
    3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * 
    cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * 
    sin( radians( lat ) ) ) 
) 
AS distance FROM stores HAVING distance < 25 ORDER BY distance LIMIT 0 , 20;

쿼리는 각 스토어의 LAT/LNG 값에 대해 ZipCode 외국 키를 참조해야합니다. 이 모든 작업을 Django 모델 쿼리에서 어떻게 만들 수 있습니까?

도움이 되었습니까?

해결책

실행 가능합니다 Django의 원시 SQL 쿼리.

내 제안은 쿼리를 작성하여 ID 목록 (지금하고있는 것처럼 보이는 것)을 가져온 다음 ID를 사용하여 관련 모델을 끌어 당기는 것입니다 (정기적 인 비 RACL Django 쿼리에서). 데이터베이스를 전환 해야하는 경우 한 가지 더 걱정할 필요가 없도록 SQL을 가능한 한 방언 독립적으로 유지하십시오.

명확히하기 위해 다음은 다음을 수행하는 방법의 예입니다.

def get_models_within_25 (self):
    from django.db import connection, transaction
    cursor = connection.cursor()

    cursor.execute("""SELECT id, ( 
        3959 * acos( cos( radians(37) ) * cos( radians( lat ) ) * 
        cos( radians( lng ) - radians(-122) ) + sin( radians(37) ) * 
        sin( radians( lat ) ) ) )
        AS distance FROM stores HAVING distance < 25
        ORDER BY distance LIMIT 0 , 20;""")
    ids = [row[0] for row in cursor.fetchall()]

    return MyModel.filter(id__in=ids)

면책 조항으로서, 나는 Django를 작성한 지 몇 달이 지났기 때문에이 코드를 보증 할 수는 없지만 올바른 줄을 따라야합니다.

다른 팁

Tom의 답변을 추적하기 위해 SQLITE의 수학 기능이 기본적으로 부족하여 기본적으로 SQLITE에서는 작동하지 않습니다. 문제 없습니다. 추가하는 것은 매우 간단합니다.

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
        from mysite import settings
        cursor = connection.cursor()
        if settings.DATABASE_ENGINE == 'sqlite3':
            connection.connection.create_function('acos', 1, math.acos)
            connection.connection.create_function('cos', 1, math.cos)
            connection.connection.create_function('radians', 1, math.radians)
            connection.connection.create_function('sin', 1, math.sin)

        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 location_location WHERE 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)

Tom에 대한 후속 조치를 취하려면 PostgreSQL에서도 작동하는 쿼리를 원한다면 '거리'가 존재하지 않는다는 오류가 발생하기 때문에 사용할 수 없습니다.

당신은 전체 구형 법률을 WHERE 절에 넣어야합니다 (MySQL에서도 작동).

import math
from django.db import connection, transaction
from django.conf import settings

from django .db import models

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

        cursor = connection.cursor()

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

        return self.filter(id__in=ids)

위도와 경도를 선택해야합니다. 그렇지 않으면 Where 절에서 사용할 수 없습니다.

Jboxer의 답변을 추적하기 위해, 여기에는 일부 하드 코딩 된 물건을 가진 사용자 정의 관리자의 일부로 모든 것이 변수로 바뀌 었습니다.

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)

Jboxer의 응답에 따라

def find_cars_within_miles_from_postcode(request, miles, postcode=0):

    # create cursor for RAW query
    cursor = connection.cursor()

    # Get lat and lon from google
    lat, lon = getLonLatFromPostcode(postcode)

    # Gen query
    query = "SELECT id, ((ACOS(SIN("+lat+" * PI() / 180) * SIN(lat * PI() / 180) + COS("+lat+" * PI() / 180) * COS(lat * PI() / 180) * COS(("+lon+" - lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS distance FROM app_car HAVING distance<='"+miles+"' ORDER BY distance ASC"

    # execute the query
    cursor.execute(query)

    # grab all the IDS form the sql result
    ids = [row[0] for row in cursor.fetchall()]

    # find cars from ids
    cars = Car.objects.filter(id__in=ids)

    # return the Cars with these IDS
    return HttpResponse( cars )

이것은 내 차를 x 양의 마일로 되돌립니다. 이것은 잘 작동합니다. 그러나 원시 쿼리는 특정 위치에서 얼마나 멀리 떨어져 있는지 반환했는데 필드 이름은 '거리'라고 생각합니다.

자동차 물체 로이 필드 '거리'를 어떻게 반환 할 수 있습니까?

위의 제안 된 답변 중 일부를 사용하여 결과적으로 결과를 얻었으므로 [이 링크]를 사용하여 방정식을 다시 확인하기로 결정했습니다.http://www.movable-type.co.uk/scripts/latlong.html 참조로서, 방정식은 다음과 같습니다d = acos(sin(lat1)*sin(lat2) + cos(lat1)*cos(lat2)*cos(lon2-lon1) ) * 6371 어디 d 계산하는 거리는

lat1,lon1 기본 점의 좌표입니다 lat2,lon2 우리의 경우 다른 점의 좌표는 데이터베이스의 점입니다.

위의 답변에서 LocationManager 수업은 이렇게 보입니다

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
    from mysite import settings
    cursor = connection.cursor()
    if settings.DATABASE_ENGINE == 'sqlite3':
        connection.connection.create_function('acos', 1, math.acos)
        connection.connection.create_function('cos', 1, math.cos)
        connection.connection.create_function('radians', 1, math.radians)
        connection.connection.create_function('sin', 1, math.sin)

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

    return self.filter(id__in=ids)

사이트 사용 [링크http://www.movable-type.co.uk/scripts/latlong.html 확인대로, 내 결과는 일관된 곳입니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top