Когда я определенным образом использую extra
в наборе запросов Django (назовите его qs
), результат qs.count()
отличается от len(qs.all())
. Воспроизвести:
Создайте пустой проект и приложение Django, затем добавьте тривиальную модель:
class Baz(models.Model):
pass
Теперь сделайте несколько объектов:
>>> Baz(id=1).save()
>>> Baz(id=2).save()
>>> Baz(id=3).save()
>>> Baz(id=4).save()
Использование метода extra
для выбора только некоторых из них дает ожидаемое количество:
>>> Baz.objects.extra(where=['id > 2']).count()
2
>>> Baz.objects.extra(where=['-id < -2']).count()
2
Но добавьте предложение select
к extra
и обратитесь к нему в предложении where
, и счет вдруг окажется неправильным, даже если результат all()
верен:
>>> Baz.objects.extra(select={'negid': '0 - id'}, where=['"negid" < -2']).all()
[<Baz: Baz object>, <Baz: Baz object>] # As expected
>>> Baz.objects.extra(select={'negid': '0 - id'}, where=['"negid" < -2']).count()
0 # Should be 2
Я думаю, что проблема связана с django.db.models.sql.query.BaseQuery.get_count()
. Он проверяет, были ли установлены атрибуты BaseQuery select
или aggregate_select
; если это так, он использует подзапрос. Но django.db.models.sql.query.BaseQuery.add_extra
добавляет только к атрибуту extra
BaseQuery, а не select
или aggregate_select
.
Как я могу исправить проблему? Я знаю, что мог бы просто использовать len(qs.all())
, но было бы неплохо иметь возможность передавать extra
ed-набор запросов в другие части кода, и эти части могут вызывать count()
, не зная, что он не работает.