Django 计数 RawQuerySet
嘿,我在用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 )
它返回的是:
Car_Deferred_model_id_user_id object
有什么想法吗?
4 个回答
7
这是一个改进后的解决方案,基于用户871977的内容:
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))
8
说实话,如果你只是想知道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 )
这样做会动态修改RawQuerySet,让它能响应len()这个功能。
这样在性能上要好得多,不过有一个潜在的缺点:如果你多次使用RawQuerySet,可能就需要放弃这个动态的_len_实现。
你们知道_len_方法会受到调用者执行环境的限制吗?如果在Apache上使用MOD_WSGI,这是否意味着调用者进程中的所有线程都会共享这个修改后的定义?
31
使用 '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))
顺便提一下,关于 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/ ]