К сожалению, нет никакой возможности (что я знаю .. я выглядел довольно трудно), чтобы избежать использования некоторых вид сырой 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