Выберите последнюю запись в группе с упорядочиванием

У меня проблемы с написанием запроса с использованием 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 модель раздел документации .

Вернуться на верх