Django删除除查询集的最后五个之外的所有内容

时间:2009-12-05 05:17:30

标签: python django

我在这里有一个超级简单的django模型:

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

使用ajax,我每分钟检查一下新邮件。我只会随时向用户显示最近的五个通知。我想避免的是以下情况。

用户登录并且没有通知。当用户的窗口启动时,他会收到10条新消息。因为我只向他展示五个,没什么大不了的。当用户开始删除他的通知时会发生此问题。如果他删除了显示的五个,那么五个旧的将在下一个ajax调用或刷新时显示。

我想让我的模型的save方法删除除了保存新对象之外的所有5个最新对象。不幸的是,你不能用[5:]来做这件事。帮助

修改

我试过这个并没有按预期工作(在模型的保存方法中):

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

我找不到奇怪行为的模式,但经过一段时间的测试后,它只会在创建新模式时删除最新的模式。我不知道为什么会这样。在模型的Meta类中处理排序(按时间戳降序)。感谢您的帮助,但我的方式似乎是唯一一致的。

3 个答案:

答案 0 :(得分:32)

这有点旧,但我相信你可以做到以下几点:

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()

答案 1 :(得分:11)

使用内部查询获取要保留的项目集,然后对其进行过滤。

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

在使用之前仔细检查一下。我发现更简单的内部查询并不总是按预期运行。我遇到的奇怪行为仅限于只是order_by和slice的查询集。由于你必须过滤用户,你应该没事。

答案 2 :(得分:8)

这就是我最终做到这一点的方式。

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

因为我在save方法中这样做,所以如果用户一次收到多个通知,循环必须运行多次的唯一方法就是这样。我并不担心这种情况发生(虽然它可能会发生,但不足以导致问题)。