Django Удалить все, кроме последних пяти запросов

У меня есть супер простая модель django:

class Notification(models.Model):
    message = models.TextField()
    user = models.ForeignKey(User)
    timestamp = models.DateTimeField(default=datetime.datetime.now)

Используя ajax, я проверяю новые сообщения каждую минуту. Я показываю только пять последних уведомлений пользователю в любое время. То, что я пытаюсь избежать, - это следующий сценарий.

Пользователь регистрируется и не имеет уведомлений. Пока окно пользователя завершено, он получает 10 новых сообщений. Поскольку я только показываю ему пять, неважно. Проблема возникает, когда пользователь начинает удалять свои уведомления. Если он удалит пять отображаемых, пять старых будут отображены в следующем вызове ajax или обновлении.

Я бы хотел, чтобы мой метод сохранения модели удалял все, кроме 5 самых последних объектов, когда новый сохраняется. К сожалению, вы не можете использовать [5:] для этого. Помощь?

ИЗМЕНИТЬ

Я пробовал это, который не работал должным образом (в методе сохранения модели):

    notes = Notification.objects.filter(user=self.user)[:4]
    Notification.objects.exclude(pk__in=notes).delete()

Я не мог найти шаблон в странном поведении, но через некоторое время тестирования он удалит только последний, когда будет создан новый. У меня нет идеи, почему это было бы. упорядочивание выполняется в модели Meta class (по убыванию времени). спасибо за помощь, но мой способ, кажется, единственный, который работает последовательно.

Ответ 1

Это немного устарело, но я считаю, что вы можете сделать следующее:

notes = Notification.objects.filter(user=self.user)[:4]
Notification.objects.exclude(pk__in=list(notes)).delete()  # list() forces a database hit.

Он стоит два раза, но избегает использования цикла for с промежуточным программным обеспечением транзакций.

Причина в том, что Django создает один запрос, а в Mysql 5.1 это вызывает ошибку

(1235, "This version of MySQL doesn't yet support 'LIMIT & IN/ALL/ANY/SOME subquery'")

Используя list(notes), мы вынуждаем запрос notes, избегая этого. Это может быть дополнительно оптимизировано для:

notes = Notification.objects.filter(user=self.user)[:4].values_list("id", flat=True)  # only retrieve ids.
Notification.objects.exclude(pk__in=list(notes)).delete()

Ответ 2

Используйте внутренний запрос, чтобы получить набор элементов, которые вы хотите сохранить, и затем фильтровать их.

objects_to_keep = Notification.objects.filter(user=user).order_by('-created_at')[:5]
Notification.objects.exclude(pk__in=objects_to_keep).delete()

Дважды проверьте это, прежде чем использовать его. Я обнаружил, что более простые внутренние запросы не всегда ведут себя так, как ожидалось. Странное поведение, которое я испытал, ограничено запросами, которые являются просто order_by и срезом. Поскольку вам придется фильтровать на пользователя, вы должны быть в порядке.

Ответ 3

вот как я это сделал.

    notes = Notification.objects.filter(user=self.user)
    for note in notes[4:]:
        note.delete()

потому что я делаю это в методе сохранения, единственный способ, который цикл должен был запускать более одного раза, будет, если пользователь сразу получит несколько уведомлений. я не беспокоюсь о том, что это происходит (хотя может случиться, что это вряд ли будет достаточно, чтобы вызвать проблему).