Прежде всего, я укажу, что:
ContactGroup.record_set.extra(where=["history_date = (select max(history_date) from app_record r where r.id=app_record.id and r.history_date <= '2009-07-18')"])
не даст вам такой же эффект, как:
records_i_want = group.record_set.most_recent_record_for_every_contact()
Первый запрос возвращает каждую запись, связанную с определенной группой (или связанную с любым из контактов определенной группы), у которой запись-дата меньше, чем дата / время, указанные в дополнительном сообщении. Запустите это в оболочке, а затем сделайте это, чтобы просмотреть запрос, созданный django:
from django.db import connection
connection.queries[-1]
, который показывает:
'SELECT "contacts_record"."id", "contacts_record"."contact_id", "contacts_record"."group_id", "contacts_record"."record_date", "contacts_record"."name", "contacts_record"."email" FROM "contacts_record" WHERE "contacts_record"."group_id" = 1 AND record_date = (select max(record_date) from contacts_record r where r.id=contacts_record.id and r.record_date <= \'2009-07-18\')
Не совсем то, что вы хотите, верно?
Теперь функция агрегирования используется для извлечения агрегированных данных, а не объектов, связанных с агрегированными данными. Поэтому, если вы пытаетесь свести к минимуму количество запросов, выполняемых с использованием агрегации, при попытке получить group.record_set.most_recent_record_for_every_contact () , у вас ничего не получится.
Без использования агрегации вы можете получить самую последнюю запись для всех контактов, связанных с группой, используя:
[x.record_set.all().order_by('-record_date')[0] for x in group.contact_set.all()]
Используя агрегацию, я смог найти следующее:
group.record_set.values('contact').annotate(latest_date=Max('record_date'))
Последний возвращает список словарей, таких как:
[{'contact': 1, 'latest_date': somedate }, {'contact': 2, 'latest_date': somedate }]
Таким образом, одна запись для каждого контакта в данной группе и даты последней записи, связанной с ним.
В любом случае, минимальный номер запроса, вероятно, составляет 1 + # контактов в группе. Если вам интересно получить результат с помощью одного запроса, это также возможно, но вам придется конструировать свои модели по-другому. Но это совсем другой аспект вашей проблемы.
Надеюсь, это поможет вам понять, как решить проблему с помощью агрегации / обычных функций ORM.