Django Удалить все, кроме последних пяти из набора запросов - PullRequest
24 голосов
/ 05 декабря 2009

У меня есть супер простая модель Джанго здесь:

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

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

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

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

EDIT

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

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

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

Ответы [ 3 ]

33 голосов
/ 08 января 2014

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

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

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

Причиной использования list(notes) является то, что 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()
11 голосов
/ 05 декабря 2009

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

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

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

8 голосов
/ 05 декабря 2009

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...