2010-02-23 81 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