Как добавить поле, не относящееся к базе данных, в модель Django, управляемую базой данных, и установить его с помощью QuerySet, сохраняя его тип данных? - PullRequest
1 голос
/ 03 сентября 2010

У меня есть модель Django, содержащая различные поля модели базы данных.Один из наборов запросов менеджера извлекает различные агрегаты с помощью некоторых аннотированных вызовов.Некоторые из этих аннотаций сделаны на заказ и извлекают значения с плавающей точкой из базы данных.Эти аннотации не являются частью полей модели.Однако когда создается набор запросов, эти числа с плавающей точкой оказываются целыми числами в модели, я полагаю, потому что нет поля модели, которое связывало бы их с типом данных с плавающей запятой или десятичным типом.

Вот некоторый код для демонстрациичто я имею в виду:

Пользовательские агрегатные классы.Обратите внимание, что база данных преобразует результат в число с плавающей запятой:

class SqlCTR(aggregates.Sum):
    is_ordinal = True
    sql_function = 'SUM' 
    sql_template= "CASE WHEN sum(campaignmanager_adstats.impressions) > 0 THEN sum(campaignmanager_adstats.clicks)/sum(campaignmanager_adstats.impressions)::float ELSE 0::float END"

class CTR(Sum):
    name='CTR'
    def add_to_query(self, query, alias, col, source, is_summary):
        aggregate = SqlCTR(col, source=source, is_summary=is_summary)
        query.aggregates[alias] = aggregate

А вот набор запросов:

camps =  self.select_related(depth=3).\      
  annotate( impressions=Sum('ad__adstats__impressions'),\      
  clicks=Sum('ad__adstats__clicks'),\      
  ctr=CTR('ad__adstats__clicks'),\      
  exclude(**campaignExclude).\      
  filter(**campaignArgs).order_by(sortBy)

Проблема в том, что, хотя сам запрос выполняется нормально и возвращает CTR в виде чисел с плавающей запятой, сортируетэто как число с плавающей запятой и просто его фильтрует (если я запускаю сгенерированный sql в консоли Postgres), результирующий набор Queryset преобразует значение в целое число, что приводит к нулю ... (Помните, CTR не является полем модели).

Как я могу убедиться, что аннотированные значения загружаются в свой правильный тип данных для модели?Могу ли я установить поле не для модели базы данных DecimalField или FloatField, которое сохранит тип?

Любая идея будет высоко оценена!
Спасибо
Harel

Ответы [ 3 ]

0 голосов
/ 03 сентября 2010

Этот код демонстрирует вывод из оболочки django после попытки предложения Омера, приведенного ниже ... Не могу написать какой-либо код в комментариях ...

>>> usr = User.objects.get(username='harel')  
>>> camps = Campaign.objects.campaigns(usr, {'ctr__gt':0, 'sort':'ctr','dir':'DESC'})  
>>> for c in camps:  
...     print "%s:: %d/%d=%d  (ctr type is %s)" % (c, c.clicks, c.impressions, c.ctr, str(type(c.ctr)))  
.    ..   
Dan Schedule Test:: 10/15135=0  (ctr type is <type 'int'>)  
DTR-04-06:: 35/101827=0  (ctr type is <type 'int'>)  
US-Advertising-ad4:: 1/2991=0  (ctr type is <type 'int'>)  
Harels Test New Camp:: 51/153929=0  (ctr type is <type 'int'>)  
Commercial Team:: 161/512072=0  (ctr type is <type 'int'>)  
US-Marketing-ad3:: 1/3405=0  (ctr type is <type 'int'>)  
0 голосов
/ 06 сентября 2010

Я отвечу на свой вопрос: Оказывается (очевидно), что прохождение самого кода django очень помогает. Мой вызов SqlCTR имел: is_ordinal = True, что комментарии в состоянии кода django:

is_ordinal, a boolean indicating if the output of this aggregate
           is an integer (e.g., a count)

пока мне нужно is_computer=True

is_computed, a boolean indicating if this output of this aggregate
           is a computed float (e.g., an average), regardless of the input
           type.
0 голосов
/ 03 сентября 2010

В соответствии с документацией в коде django:

source является базовым определением поля или агрегата для ссылки на столбец.Если агрегат не является порядковым или вычисляемым типом, эта ссылка используется для определения принудительного типа вывода агрегата.

Итак, попробуйте поместить тип поля в источник в конструкторе SqlCTR.

aggregate = SqlCTR(col, source=source, is_summary=is_summary)

должно быть:

aggregate = SqlCTR(col, source=models.DecimalField(), is_summary=is_summary)
...