Django count RawQuerySet - PullRequest
       24

Django count RawQuerySet

19 голосов
/ 23 февраля 2010

Слушай, я использую 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 ]

26 голосов
/ 23 февраля 2010

Используйте функцию 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/]

7 голосов
/ 12 августа 2013

По правде говоря, если все, что вам нужно, это общее количество записей в RawQuerySet, то во всех случаях вам следует избегать приведения RawQuerySet в список.

Приведение RawQuerySet в список будет повторять каждую запись, соответствующую запросу. Это потенциально обременительно для сервера. Вместо этого используйте количество (). Это может быть достигнуто путем оборачивания счетчика () вокруг необработанного 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, означает ли это, что все потоки в процессе вызывающей стороны будут использовать измененное определение?

4 голосов
/ 17 марта 2016

Вот улучшенное решение, основанное на пользовательских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))
2 голосов
/ 08 февраля 2013

Причина, по которой счетчик отсутствует, заключается в том, что вам потребуется дополнительный запрос "count (*)" к базе данных, чтобы узнать размер вашего результирующего набора.

Имейте в виду, что вызов list(cars) загружает все ваши результаты в память. Это позволяет получить счет с len, но может оказаться дорогостоящей операцией, если у вас большой набор результатов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...