Django count 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 ответа
Используйте функцию 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/ ]
По правде говоря, если все, что вам нужно, это общее количество записей в RawQuerySet, то вы должны избегать приведения RawQuerySet в список.
Приведение RawQuerySet в список будет повторять каждую запись, соответствующую запросу. Это потенциально обременительно для сервера. Вместо этого используйте count (). Этого можно достичь, обернув count () вокруг необработанного SQL, который вы использовали для порождения RawQuerySet.
Я использовал это, чтобы решить проблему:
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 _ ограничен контекстом выполнения вызывающей стороны? Если вы используете MOD_WSGI в Apache, означает ли это, что все потоки в процессе вызывающей стороны будут использовать измененное определение?
Вот улучшенное решение, основанное на 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))
Причина, по которой счетчик отсутствует, заключается в том, что вам потребуется дополнительный запрос count(*) к базе данных, чтобы узнать размер вашего результирующего набора.
Так что имейте в виду, что призвание list(cars)
загружает все ваши результаты в память. Это позволяет получить счет с len
, но может быть дорогой операцией, если у вас большой набор результатов.