2010-02-23 46 views
18

干草,我使用Django 1.2,我想知道如何计算原始查询集(RawQuerySet)的行数。Django count 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 

任何想法?

回答

21

使用'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/ ]

+3

收到此错误 型“RawQuerySet”的对象没有LEN() – dotty 2010-02-23 11:25:28

+8

LEN(名单(轿车))似乎工作我投后该对象作为列表 – dotty 2010-02-23 11:30:15

+0

好的,我已经更新了相应的答案。 – msanders 2010-02-23 11:39:49

2

没有'count'的原因是因为您需要额外的“count(*)”查询到数据库才能知道结果集的大小。

请记住,调用list(cars)会将所有结果加载到内存中。这可以让你得到len的计数,但是如果你有一个大的结果集,可能是一个昂贵的操作。

+0

这只适用于查询返回至少一行,否则计数将不会在任何地方:-) – 2014-06-19 19:47:42

6

真相被告知,如果你想要的只是RawQuerySet中记录的总数,那么你应该避免将RawQuerySet转换为列表。

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

我用这个解决问题:

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,这是否意味着调用者进程中的所有线程将共享修改的定义?

2

这是基于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)) 
+0

而不是手动将参数注入到sql字符串应该将它们传递到'cursor.execute(sql,self.params) ' – serg 2018-02-12 20:51:42

+0

@serg调用'cursor.execute(sql,[params])'如果基于Django文档在'https://docs.djangoproject.com/zh/2.0/topics/db/sql/#executing-custom-sql -directly'。谢谢! – caot 2018-02-14 13:46:09