Django 查询集';s'count'在'extra'之后是错误的`
当我在Django查询集(称之为Django 查询集';s'count'在'extra'之后是错误的`,django,Django,当我在Django查询集(称之为qs)上以某种方式使用extra时,qs.count()的结果不同于len(qs.all())。复制: 创建一个空的Django项目和应用程序,然后添加一个普通模型: class Baz(models.Model): pass 现在制作几个对象: >>> Baz(id=1).save() >>> Baz(id=2).save() >>> Baz(id=3).save() >>> Ba
qs
)上以某种方式使用extra
时,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
我认为问题与django.db.models.sql.query.BaseQuery.get\u count()
有关。它检查BaseQuery的select
或aggregate\u select
属性是否已设置;如果是,则使用子查询。但是django.db.models.sql.query.BaseQuery.add\u extra
只添加到BaseQuery的extra
属性,而不是select
或aggregate\u select
我怎样才能解决这个问题?我知道我可以只使用len(qs.all())
,但如果能够将额外的'ed查询集传递给代码的其他部分就好了,这些部分可以调用count()
,而不知道它已损坏。重新定义get\u count()
和monkeypatching似乎可以解决问题:
def get_count(self):
"""
Performs a COUNT() query using the current filter constraints.
"""
obj = self.clone()
if len(self.select) > 1 or self.aggregate_select or self.extra:
# If a select clause exists, then the query has already started to
# specify the columns that are to be returned.
# In this case, we need to use a subquery to evaluate the count.
from django.db.models.sql.subqueries import AggregateQuery
subquery = obj
subquery.clear_ordering(True)
subquery.clear_limits()
obj = AggregateQuery(obj.model, obj.connection)
obj.add_subquery(subquery)
obj.add_count_column()
number = obj.get_aggregation()[None]
# Apply offset and limit constraints manually, since using LIMIT/OFFSET
# in SQL (in variants that provide them) doesn't change the COUNT
# output.
number = max(0, number - self.low_mark)
if self.high_mark is not None:
number = min(number, self.high_mark - self.low_mark)
return number
django.db.models.sql.query.BaseQuery.get_count = quuux.get_count
测试:
>>> Baz.objects.extra(select={'negid': '0 - id'}, where=['"negid" < -2']).count()
2
但是,我不确定此修复是否会产生其他意外后果。验证了Django 1.2.1中仍然存在此问题。
>>> Baz.objects.extra(select={'negid': '0 - id'}, where=['"negid" < -2']).count()
2
def basequery_get_count(self, using):
"""
Performs a COUNT() query using the current filter constraints.
"""
obj = self.clone()
if len(self.select) > 1 or self.aggregate_select or self.extra:
# If a select clause exists, then the query has already started to
# specify the columns that are to be returned.
# In this case, we need to use a subquery to evaluate the count.
from django.db.models.sql.subqueries import AggregateQuery
subquery = obj
subquery.clear_ordering(True)
subquery.clear_limits()
obj = AggregateQuery(obj.model)
obj.add_subquery(subquery, using=using)
obj.add_count_column()
number = obj.get_aggregation(using=using)[None]
# Apply offset and limit constraints manually, since using LIMIT/OFFSET
# in SQL (in variants that provide them) doesn't change the COUNT
# output.
number = max(0, number - self.low_mark)
if self.high_mark is not None:
number = min(number, self.high_mark - self.low_mark)
return number
models.sql.query.Query.get_count = basequery_get_count