遗憾的是没有办法(我所知道的。我看了相当困难),以避免使用一些一种原始的sql来完成你想要做的事(用你目前的模型;看到最后的另一个建议)。但是,您可以尽可能少地写入原始sql,从而将影响降至最低。在实践中,Django站点不需要跨不同数据库移植。除非你打算在别处使用这个应用程序或公开发布它,否则你应该没问题。
以下示例适用于sqlite。您可以可以保留数据库类型到date
函数的映射,查找驱动程序的类型,并根据需要使用正确的函数替换函数。
>>> for stat in Stats.objects.all():
... print stat.created, stat.growth
...
2013-06-22 13:41:25.334262+00:00 3
2013-06-22 13:41:40.473373+00:00 3
2013-06-22 13:41:44.921247+00:00 4
2013-06-22 13:41:47.533102+00:00 5
2013-06-23 13:41:58.458250+00:00 6
2013-06-23 13:42:01.282702+00:00 3
2013-06-23 13:42:03.633236+00:00 1
>>> last_stat_per_day = Stats.objects.extra(
select={'the_date': 'date(created)' }
).values_list('the_date').annotate(max_date=Max('created'))
>>> last_stat_per_day
[(u'2013-06-22', datetime.datetime(2013, 6, 22, 13, 41, 47, 533102, tzinfo=<UTC>)), (u'2013-06-23', datetime.datetime(2013, 6, 23, 13, 42, 3, 633236, tzinfo=<UTC>))]
>>> max_dates = [item[1] for item in last_stat_per_day]
>>> max_dates
[datetime.datetime(2013, 6, 22, 13, 41, 47, 533102, tzinfo=<UTC>),
datetime.datetime(2013, 6, 23, 13, 42, 3, 633236, tzinfo=<UTC>)]
>>> stats = Stats.objects.filter(created__in=max_dates)
>>> for stat in stats:
... print stat.created, stat.growth
...
2013-06-22 13:41:47.533102+00:00 5
2013-06-23 13:42:03.633236+00:00 1
我在这里写之前,这只是一个单一的查询,但我撒谎 - 在values_list需要转换到只返回MAX_DATE为连续查询,这意味着运行的语句。尽管只有2个查询,但它会比N + 1函数好得多。
非便携式位是这样的:
last_stat_per_day = Stats.objects.extra(
select={'the_date': 'date(created)' }
).values_list('the_date').annotate(max_date=Max('created'))
使用extra
并不理想,但这里的原始的SQL语句简单,很好地适合于数据库驱动程序相关的替代品。只需要更换date(created)
。如果你喜欢,你可以用自定义管理器的方法把它包装起来,然后你可以在一个位置成功地抽象出这个混乱。
另一种方法是只在模型中添加一个DateField
,然后根本不需要额外使用。您只需将values_list
呼叫替换为values_list('created_date')
,完全删除extra
,然后每天给它打电话。成本显而易见 - 需要更多的存储空间。这对于为什么在同一模型上有Date
和DateTime
字段也是非直观的。保持两者同步也可能造成问题。
只是为了得到这个清晰的在我的脑海;如果你想要每一天的最新消息 - 在你的榜样中你会不想要200和222增长? – Ewan
是的,没错。我纠正了它;) – Jannis