我有一堆具有值和日期字段的对象:
obj1 = Obj(date='2009-8-20', value=10)
obj2 = Obj(date='2009-8-21', value=15)
obj3 = Obj(date='2009-8-23', value=8)
我希望退回:
[10, 15, 0, 8]
或者更好的是,总计到那一点的总和:
[10, 25, 25, 33]
我最好直接从数据库中获取这些数据,但是否则我可以很容易地使用forloop进行总计。
我正在使用Django的ORM和Postgres
编辑:
请注意,我的例子仅涵盖了几天,但在实践中,我有数百个对象覆盖了几十年...我想要做的是创建一个线图,显示所有的总和我的物体随着时间的推移而增长(很长一段时间)
答案 0 :(得分:4)
这个没有经过测试,因为设置一个Django表进行测试有点太痛苦了:
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)]
这可以避免每天运行单独的查询。
答案 1 :(得分:0)
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
如果每个日期有多个Obj,则需要检查len(obj)并迭代它们以防它超过1。
答案 2 :(得分:0)
如果您遍历Obj.objects.get 100次,那么您正在进行100次SQL查询。 Obj.objects.filter将在一个SQL查询中返回结果,但您也选择所有模型字段。正确的方法是使用Obj.objects.values_list,它将使用单个查询执行此操作,并且只选择“值”字段。
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]
要执行val_list的运行聚合,你可以这样做(不确定这是最pythonic方式)
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]
编辑:如果你需要解释缺少的日子,@ Glenn Maynard的答案实际上相当不错,虽然我更喜欢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]