Python Django删除queryset中除最后五个之外的所有内容

Python Django删除queryset中除最后五个之外的所有内容,python,django,Python,Django,我这里有一个超级简单的django模型: class Notification(models.Model): message = models.TextField() user = models.ForeignKey(User) timestamp = models.DateTimeField(default=datetime.datetime.now) 使用ajax,我每分钟都会检查新消息。我在任何时候都只向用户显示最近的五个通知。我试图避免的是以下情况 用户登录并且

我这里有一个超级简单的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:]来执行此操作。帮忙

编辑

我尝试了这个方法,但没有按预期效果(在模型的保存方法中):


我在奇怪的行为中找不到模式,但经过一段时间的测试,它只会在创建新模式时删除最近的模式。我不知道为什么会这样。排序在模型的元类中进行(通过时间戳降序)。感谢您的帮助,但我的方式似乎是唯一一种能够始终如一地工作的方式。

使用内部查询获取您想要保留的项目集,然后对其进行筛选

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

使用前请仔细检查。我发现更简单的内部查询并不总是像预期的那样运行。我所经历的奇怪行为仅限于仅是一个订单和一个切片的查询集。因为您必须根据用户进行筛选,所以您应该很好。

这就是我最终这样做的原因

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

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

这有点过时,但我相信您可以做到以下几点:

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

我尝试了一种类似的方法,它很奇怪。当它到达某一点时,它删除了用户的所有对象。我相信这与切片如何处理惰性查询集有关。我希望能为这种古怪的行为提供更多的数据点。对我来说,如果没有筛选器(),order_by似乎从内部查询中剥离。您是否在Model.objects.filter(…).orber_by(…)[:5]内部查询中遇到奇怪的行为?哦,您可能会发现.query.as_sql()很有用。我已经用我尝试过的代码编辑了我的问题。我没有删除所有对象的代码,但我尝试了上面的代码(甚至更类似于您的代码),但这并没有像我预期的那样起作用。我喜欢在尝试跟踪问题时非常明确地说明问题。您可能希望显式地向内部查询中添加并按('-created_at')排序。此外,您还可以尝试使用.query.as_sql()查看原始sql
.delete()
没有.query属性,请将其删除并添加.query.as\u sql()以查看发生了什么。哦,在./manage.py shell中可能最容易做到这一点。我可以在MySQL 5.1中添加这一点:django.db.utils.DatabaseError:(1235,“此版本的MySQL还不支持“LIMIT&in/ALL/ANY/SOME子查询”),这是完全有效的。您已经知道,对于for循环中的每个删除操作,都将得到一个sql操作。感谢您的更新。在方法上划出上面几行,并在其周围添加commit_on_success decorator,以确保它保持快速,即使有许多查询需要进行。这是一个很好的可扩展回答,有助于强调您不能在切片上使用delete的事实在文档中有解释:-它引发了一个
不能使用的问题带有删除的“限制”或“偏移”错误。我希望自09年以来,情况有所改变,但“for”解决方案似乎仍然是唯一的解决方案!我甚至没有django环境,但我相信这是一个比我的for循环更好的解决方案。在更大的数据集上很可能是更好的解决方案,但我认为for循环更容易阅读。
notes = Notification.objects.filter(user=self.user)[:4].values_list("id", flat=True)  # only retrieve ids.
Notification.objects.exclude(pk__in=list(notes)).delete()