Django计算RawQuerySet

dot*_*tty 19 python django count

Hay,我正在使用django 1.2,我想知道如何计算原始查询集(RawQuerySet)中的行.

传统的.count()方法不起作用.

继承人我的疑问

query = "SELECT *, ((ACOS(SIN(%s * PI() / 180) * SIN(lat * PI() / 180) + COS(%s * PI() / 180) * COS(lat * PI() / 180) * COS((%s - lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS distance FROM app_car WHERE price BETWEEN %s AND %s HAVING distance<=%s ORDER BY distance ASC"

cars = Car.objects.raw(query, [lat, lat, lon, min_price, max_price, miles])

return HttpResponse( cars )
Run Code Online (Sandbox Code Playgroud)

它的回归

Car_Deferred_model_id_user_id object
Run Code Online (Sandbox Code Playgroud)

有任何想法吗?

msa*_*ers 27

使用'len()'函数.这会给:

query = "SELECT *, ((ACOS(SIN(%s * PI() / 180) * SIN(lat * PI() / 180) + COS(%s * PI() / 180) * COS(lat * PI() / 180) * COS((%s - lon) * PI() / 180)) * 180 / PI()) * 60 * 1.1515) AS distance FROM app_car WHERE price BETWEEN %s AND %s HAVING distance<=%s ORDER BY distance ASC"

cars = Car.objects.raw(query, [lat, lat, lon, min_price, max_price, miles])

return HttpResponse(len(list(cars))
Run Code Online (Sandbox Code Playgroud)

旁白:有关Django 1.2 Model.objects.raw()方法的一些有用信息,请访问:http://djangoadvent.com/1.2/smoothing-curve/ [看起来该网站可能已过期,但互联网档案馆有:http://web.archive.org/web/20110513122309/http://djangoadvent.com/1.2/smoothing-curve/ ]

  • len(list(cars))似乎在我将对象转换为列表后工作 (9认同)
  • 获取"RawQuerySet"类型的此错误对象没有len() (5认同)
  • 我也想知道是否可以通过使用'SELECT COUNT(*)'来优化它(假设你需要的只是行数,而不是行本身).我目前没有安装1.2,所以不能试试. (4认同)

小智 7

说实话,如果您想要的只是RawQuerySet中的记录总数,那么无论如何都应该避免将RawQuerySet转换为列表.

将RawQuerySet转换为列表将遍历与查询匹配的每个记录.这对服务器来说可能很麻烦.请改用count().这可以通过在您用于生成RawQuerySet的原始SQL周围包装count()来实现.

我用它来解决问题:

def add_len_protocol_to_raw_sql_query( query ):
    """
    Adds/Overrides a dynamic implementation of the length protocol to the definition of RawQuerySet for the remainder of this thread's lifespan
    """
    from django.db.models.query import RawQuerySet
    def __len__( self ):
        from django.db import connection
        sql = 'SELECT COUNT(*) FROM (' + query + ') B;'
        cursor = connection.cursor()
        cursor.execute( sql )
        row = cursor.fetchone()
        return row[ 0 ]
    setattr( RawQuerySet, '__len__', __len__ )
query = 'SELECT * FROM A_TABLE_OF_MINE'
add_len_protocol_to_raw_sql_query( query )
Run Code Online (Sandbox Code Playgroud)

这会对RawQuerySet进行动态修改,以便它响应len()协议.

这在性能方面要好得多,你可能存在一个缺点:如果你不止一次使用RawQuerySet,那么放弃动态_ len _实现是可取的.

你是否知道_ len _方法是否会被调用者的执行上下文约束?如果在Apache上使用MOD_WSGI,这是否意味着调用者进程中的所有线程将共享修改后的定义?


cao*_*aot 6

这是基于 user871977 的改进解决方案:

from django.db import connection

def get_len(rawqueryset):
    def __len__(self):
        params = ["""'%s'""" % p for p in self.params]
        sql = 'SELECT COUNT(*) FROM (' + (rawqueryset.raw_query % tuple(params)) + ') B;'
        cursor = connection.cursor()
        cursor.execute(sql)
        row = cursor.fetchone()
        return row[0]
    return __len__

rawqueryset = .... # a RawQuerySet instance
setattr(type(rawqueryset), '__len__', get_len(rawqueryset))
Run Code Online (Sandbox Code Playgroud)