Unfortunately, there is no way (what I know about .. I looked pretty hard) to avoid using some kind of raw sql to accomplish what you want to do (with your current model; another suggestion) . But you can minimize the impact by writing as little raw sql as possible. In practice, django sites should not be portable across different databases. If you do not plan to use this application elsewhere or publicly publish it, you should be fine.
Below is an example for sqlite. You can save the mapping of database types to date functions, see the type of driver and replace it with the correct one if you need to.
>>> 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
I wrote here earlier that this was only one request, but I lied - list_value needs to be converted in order to return max_date for the next request, which means the statement is executed. These are just 2 questions, which would be significantly better than the N + 1 function.
Not portable bit:
last_stat_per_day = Stats.objects.extra( select={'the_date': 'date(created)' } ).values_list('the_date').annotate(max_date=Max('created'))
Using extra not ideal, but the source sql here is simple and perfectly suited for database dependent driver replacement. Only date(created) needs to be replaced. You can wrap this method in the user manager if you want, and then you successfully canceled this mess in one place.
Another option is to simply add a DateField to your model, and then you do not need to use additional files at all. You simply replace the values_list call with values_list('created_date') , completely remove extra and name it day. The cost is obvious - more storage space is required. It is also unintuitive why you have a date and DateTime field on the same model. Keeping two in sync can also cause problems.