2010-01-06 2 views
0

장고 쿼리 세트 (qs)에서 특정 방식으로 extra을 사용하면 의 결과는 len(qs.all())과 다릅니다. 재현하려면 : 단지의 일부를 선택 extra 방법을 사용하여여분의 후 queryset의`count`가 잘못되었습니다.

>>> Baz(id=1).save() 
>>> Baz(id=2).save() 
>>> Baz(id=3).save() 
>>> Baz(id=4).save() 

:

class Baz(models.Model): 
    pass 

지금 몇 개체를 만들 :

장고 프로젝트와 응용 프로그램 빈을 확인한 다음 사소한 모델을 추가 예상 카운트가 생성됩니다.

>>> Baz.objects.extra(where=['id > 2']).count() 
2 
>>> Baz.objects.extra(where=['-id < -2']).count() 
2 

그러나 selectextra에 절과는 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_extraselect 또는 aggregate_select이 아닌 BaseQuery의 extra 속성에만 추가됩니다.

어떻게 문제를 해결할 수 있습니까? 나는 단지 len(qs.all())을 사용할 수 있다는 것을 알고 있지만 extra 'ed queryset을 코드의 다른 부분으로 전달할 수 있으면 좋을 것입니다. 그리고 그 부분은 깨 졌음을 알지 못하며 count()으로 전화 할 수 있습니다.

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 

테스트 : get_count() 및 monkeypatching 재정

+0

Django 1.2.1에서 문제가 계속 발생하는지 확인했습니다. –

답변

0

이 문제를 해결하기 위해 나타납니다

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 

아니에요 : 장고 1.2.1와 함께 작동하도록 업데이트

>>> Baz.objects.extra(select={'negid': '0 - id'}, where=['"negid" < -2']).count() 
2 

그러나이 픽스가 다른 의도하지 않은 결과를 가져올 지 확신하십시오.

관련 문제