Pergunta

Eu tenho um monte de objetos que têm um campo de valor e data:

obj1 = Obj(date='2009-8-20', value=10)
obj2 = Obj(date='2009-8-21', value=15)
obj3 = Obj(date='2009-8-23', value=8)

Eu quero isso devolvido:

[10, 15, 0, 8]

Ou melhor ainda, um agregado do total até esse ponto:

[10, 25, 25, 33]

Eu seria melhor obter esses dados diretamente do banco de dados, mas, caso contrário, posso fazer o total facilmente com um forloop.

Estou usando o Django's Orm e também o Postgres

editar:

Apenas para observar que meu exemplo abrange apenas alguns dias, mas na prática, tenho centenas de objetos cobrindo algumas décadas ... o que estou tentando fazer é criar um gráfico de linha mostrando como a soma de todos os meus objetos tem crescido com o tempo (muito tempo)

Foi útil?

Solução

Este não é testado, pois é um pouco demais para configurar uma tabela de django para testar com:

from datetime import date, timedelta
# http://www.ianlewis.org/en/python-date-range-iterator
def datetimeRange(from_date, to_date=None):
    while to_date is None or from_date <= to_date:
        yield from_date
        from_date = from_date + timedelta(days = 1)

start = date(2009, 8, 20)
end = date(2009, 8, 23)
objects = Obj.objects.filter(date__gte=start)
objects = objects.filter(date__lte=end)

results = {}
for o in objects:
    results[o.date] = o.value

return [results.get(day, 0) for day in datetimeRange(start, end)]

Isso evita executar uma consulta separada para todos os dias.

Outras dicas

result_list = []
for day in range(20,24):    
    result = Obj.objects.get(date=datetime(2009, 08, day))
    if result:
        result_list.append(result.value)
    else:
        result_list.append(0)
return result_list

Se você tiver mais de um OBJ por data, precisará verificar Len (OBJ) e itera sobre eles, caso seja mais de 1.

Se você percorrer um obj.Objects.get 100 vezes, estará fazendo 100 sql consultas. Obj.Objects.Filter retornará os resultados em uma consulta SQL, mas você também seleciona todos os campos de modelo. A maneira certa de fazer isso é usar obj.objects.values_list, que fará isso com uma única consulta e selecionar apenas o campo 'valores'.

start_date = date(2009, 8, 20)
end_date = date(2009, 8, 23)

objects = Obj.objects.filter(date__range=(start_date,end_date))
# values_list and 'value' aren't related. 'value' should be whatever field you're querying
val_list = objects.values_list('value',flat=True)
# val_list = [10, 15, 8]

Para fazer um agregado em execução da Val_list, você pode fazer isso (não tem certeza de que essa é a maneira mais pitônica)

for i in xrange(len(val_list)):
    if i > 0:
        val_list[i] = val_list[i] + val_list[i-1]

# val_list = [10,25,33]

EDIT: Se você precisar explicar os dias ausentes, a resposta de @Glenn Maynard é realmente muito boa, embora eu prefira a sintaxe dict ():

objects = Obj.objects.filter(date__range=(start_date,end_date)).values('date','value')
val_dict = dict((obj['date'],obj['value']) for obj in objects)
# I'm stealing datetimeRange from @Glenn Maynard
val_list = [val_dict.get(day, 0) for day in datetimeRange(start_date, end_date)]
# val_list = [10,15,0,8]
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top