Выберите последнюю запись в группе с упорядочиванием
У меня проблемы с написанием запроса с использованием Django ORM, я хочу найти последнюю запись в каждой группе. Я помещаю сообщения чата в модель и хочу найти последний чат каждого пользователя и показать чаты последнего чата каждого пользователя и с последним чатом пользователя на главном экране, как в WhatsApp, Skype или подобных приложениях. В настоящее время я использую следующий запрос,
Chats.objects.all().order_by('user_id', '-date').distinct('user_id')
Используя это, я могу получить последний чат каждого пользователя, но я не могу получить правильную последовательность. Результат запроса находится в порядке, в котором пользователи были созданы в базе данных, что, как я понимаю, правильно, но я хочу показать пользователя, который отправил последний чат, вверху.
Мой Models.py
class Chats(models.Model):
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
chat = models.CharField(max_length=1023, null=True, blank=True)
date = models.DateTimeField(auto_now_add=True)
Большое спасибо, пожалуйста, дайте мне знать, если потребуется любая другая информация.
Вариант 1: Заказ на уровне Django/Python
Сначала элементы сортируются по user_id
, и только в случае равенства берется тот, у которого самая поздняя дата. Но это означает, что в итоге для каждого пользователя вы получите объект Chats
, упорядоченный по user_id
.
Я думаю, что здесь ваш единственный вариант - это сортировка на уровне Django/Python, поэтому оберните их в список и сортируйте по date
:
from operator import attrgetter
items = list(Chats.objects.order_by('user_id', '-date').distinct('user_id'))
items.sort(key=attrgetter('date'), reverse=True)
# work with items
и затем отобразите items
в шаблоне.
Вариант 2: Аннотируйте модель User
вместо
Другой вариант - аннотировать User
модель и таким образом работать с QuerySet
из User
объектов:
from django.db.models import Max, OuterRef, Subquery
User.objects.filter(
chats__isnull=False
).annotate(
last_date=Max('chats__date'),
last_message=Subquery(
Chat.objects.filter(user_id=OuterRef('pk')).order_by('-date').value('chat')[:1]
)
).order_by('-last_date')
Здесь User
объекты будут иметь дополнительный атрибут .last_date
с последним временем даты объекта, и .last_message
с этим сообщением.
Примечание: Обычно лучше использовать
settings.AUTH_USER_MODEL
[Django-doc] для ссылки на модель пользователя, чем использоватьUser
модель [Django-doc] напрямую. Для получения дополнительной информации вы можете посмотреть ссылка наUser
модель раздел документации .