Для набора запросов из одного элемента индексация 0-го элемента a (query_set[0]) и query_set.first() дают разные значения - Django 2.2.7
Я выполняю следующий код:
city_state_location = (
Location.objects.filter(city=city, state=state)
.values_list("city")
.annotate(long=Avg("longitude"), lat=Avg("latitude"))
)
print(
city_state_location,
city_state_location[0],
city_state_location.first(),
len(city_state_location),
)
Что выводит:
<QuerySet [('New York', -73.9422666666667, 40.8382)]>
('New York', -73.9422666666667, 40.8382)
('New York', -73.9501, 40.8252)
1
Почему это происходит? Набор запросов содержит только один элемент, поэтому я не понимаю, почему индексирование первого элемента отличается от вызова .first()
Это работает на Django 2.2.7
Почему это происходит?
Вопреки распространенному мнению, .first()
и [0]
отличаются. Действительно, .first()
добавит оговорку .order_by('pk')
на случай, если вы неправильно упорядочите кверисет, в результате чего не будет GROUP BY city
, так как первичный ключ является частью процесса упорядочивания, поэтому первый элемент - это просто первый Location
объект, упорядоченный по первичному ключу, который удовлетворяет заданной фильтрации, а также Avg('longitude')
и Avg('latitude')
. Действительно, если мы посмотрим на исходный код .first()
[GitHub], то увидим:
def first(self): """Return the first object of a query or None if no match is found.""" for obj in (self if self.ordered else self.order_by('pk'))[:1]: return obj
Таким образом, будет возвращена долгота и широта для первого элемента.
С другой стороны, использование [0]
не добавит дополнительный .order_by('pk')
, поэтому возвращается элемент первой группы элементов, удовлетворяющих условию фильтра, который, таким образом, определяет среднее значение всех элементов, указывающих на 'New York'
в данном случае.
Если бы вы использовали city_state_location.order_by('pk')[0]
, то произошло бы то же самое, что и при использовании .first()
.