Внешние ключи Django в выражении extra () - PullRequest
0 голосов
/ 13 мая 2018

Я пытаюсь использовать метод extra () Django, чтобы отфильтровать все объекты в определенном радиусе, как в этом ответе: http://stackoverflow.com/questions/19703975/django-sort-by-distance/26219292, но у меня возникли некоторые проблемы с выражением 'gcd'поскольку мне нужно достичь широты и долготы через два отношения внешнего ключа вместо использования полей прямой модели.

В частности, у меня есть один класс опыта:

class Experience(models.Model):   
      starting_place_geolocation = models.ForeignKey(GooglePlaceMixin, on_delete=models.CASCADE,
                                               related_name='experience_starting')
      visiting_place_geolocation = models.ForeignKey(GooglePlaceMixin, on_delete=models.CASCADE,
                                               related_name='experience_visiting')

с двумя внешними ключами к одному и тому же классу GooglePlaceMixin:

class GooglePlaceMixin(models.Model):
      latitude = models.DecimalField(max_digits=20, decimal_places=15)
      longitude = models.DecimalField(max_digits=20, decimal_places=15)
      ...

Вот мой код для фильтрацииИспытайте объекты, начиная местоположение места:

    def search_by_proximity(self, experiences, latitude, longitude, proximity):

          gcd = """
                6371 * acos(
                cos(radians(%s)) * cos(radians(starting_place_geolocation__latitude))
                * cos(radians(starting_place_geolocation__longitude) - radians(%s)) +
                sin(radians(%s)) * sin(radians(starting_place_geolocation__latitude))
                          )
                          """
          gcd_lt = "{} < %s".format(gcd)

          return experiences \
              .extra(select={'distance': gcd},
               select_params=[latitude, longitude, latitude],
               where=[gcd_lt],
               params=[latitude, longitude, latitude, proximity],
               order_by=['distance'])

, но когда я пытаюсь вызвать объект внешнего ключа "strarting_place_geolocation__latitude", он возвращает эту ошибку:

column "starting_place_geolocation__latitude" does not exist

Что я должен сделать, чтобы достичьзначение внешнего ключа?Заранее спасибо

1 Ответ

0 голосов
/ 14 мая 2018

Когда вы используете extra (чего следует избегать, как указано в документации), вы на самом деле пишете необработанный SQL.Как вы, вероятно, знаете, чтобы получить значение из ForeignKey, вы должны выполнить JOIN.При использовании Django ORM он переводит эти причудливые двойные подчеркивания в правильное предложение JOIN.Но SQL не может.И вы также не можете добавить JOIN вручную.Правильный путь здесь - придерживаться ORM и определять некоторые пользовательские функции базы данных для sin, cos, радианы и так далее.Это довольно легко.

class Sin(Func):
    function = 'SIN' 

Затем используйте это так:

qs = experiences.annotate(distance=Cos(Radians(F('starting_place_geolocation__latitude') )) * ( some other expressions)) 

Обратите внимание, что причудливые двойные подчеркивания возвращаются снова и работают, как и ожидалось. У вас есть идея.

Вот моя полная коллекция, если вам нравится копирование с SO) https://gist.github.com/tatarinov1997/3af95331ef94c6d93227ce49af2211eb

PS Вы также можете столкнуться с ошибкой set output_field.Затем вы должны заключить все выражение расстояния в ExpressionWrapper и предоставить ему аргумент output_field=models.DecimalField().

...