Django 获取切片后,无法更新查询

Django 获取切片后,无法更新查询,django,django-queryset,Django,Django Queryset,我正在尝试这样做: UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now)[0:5].update(read=True) 但我得到了这个错误: Cannot update a query once a slice has been taken. (使用django 1.2.1) 我做错了什么?正如错误所述,如果取出一个切片,就不能对查询集调用update() 原因是: 获取切片相

我正在尝试这样做:

UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now)[0:5].update(read=True)
但我得到了这个错误:

Cannot update a query once a slice has been taken.
(使用django 1.2.1)


我做错了什么?

正如错误所述,如果取出一个切片,就不能对查询集调用
update()

原因是:

  • 获取切片相当于SQL中的
    LIMIT
    语句
  • 发出更新会将查询转换为
    update
    语句
  • 你正在尝试做的将等同于

    更新。。。哪里限制5


    这是不可能的,至少在标准SQL中是不可能的。

    您不能这样做。从Django文档中:

    可以看到类似于以下内容的情况-我不确定在内部
    QuerySet中执行限制是否会绕过切片后调用
    update()
    的检查:

    inner_q = UserLog.objects.filter(user=user,
                                     action='message',
                                     timestamp__lt=now).values('pk')[0:5]
    UserLog.objects.filter(pk__in=inner_q).update(read=True)
    
    否则,您可以使用类似的方法:


    在尝试限制查询集返回的记录数时,我遇到了相同的错误

    我发现如果我们使用Django中的一个,比如,我们可以使用
    paginate\u by=
    属性来限制记录的数量

    例如(在views.py中):


    如果您想切掉查询集的一些结果,可以复制它 将其复制到另一个变量(浅拷贝就足够了,这会更快) 而不是深度复制,因为它只使用对原始的引用 对象。)

    这将防止Django抱怨,如果你有一个订单由过滤器上 你的桌子,因为如果你在主桌上做,那是在切片后发生的
    queryset对象

    由于切片发生的位置,您的代码不正确。它应该发生在调用
    update()
    之后,而不是之前

    错:

    UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now)[0:5].update(read=True)
    
    对:

    UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now).update(read=True)[0:5]
    

    自Django 2.2以来,您可以使用批量更新:

    queryset=UserLog.objects.filter(user=user.filter(action='message').filter(timestamp\uu lt=now)
    批量=[]
    对于用户登录queryset[0:5]:
    userlog.read=True
    bulk.append(userlog)
    UserLog.objects.bulk\u更新(bulk,['read'])
    
    非常感谢。我明白我的错误了。有什么解决办法吗?(除了在pks上循环并更新每个pks之外?
    UPDATE…其中…LIMIT 1在MySQL中是可能的。避免“选择…进行更新”锁定非常有用。@如果您是对的,我稍微扩展了我的答案。请注意,OP从未提及所使用的数据库类型。只要不需要分页,这是非常好和干净的。我想你也可能会抱怨你把代码弄得不清楚,因为你说它是分页的,但是没有在模板中分页,但是它比其他方法更快、更容易看出发生了什么。你可能应该把它们放在“with transaction.atomic():”块中。谢谢你的贡献。只提供代码作为答案并不能清楚地帮助OP和读者标记为正确答案。如果您提供此代码解析查询的原因和方式,这将非常有用。你在OP的代码中做了哪些更改,以解决查询。我知道。但就我而言,我不明白他的答案。然后,我这样做,我的问题就解决了。我的问题也一样。这就是为什么我把我的答案放在这里。这是一个错误的(甚至可能是危险的)答案。OP显然想更新前五个结果。我很确定你的代码会更新所有结果,然后它会抛出一个错误,因为
    update
    返回行数,并且你不能切片一个整数。这是非常低效的,因为它会加载Mytable中的所有项。
    import copy
    
    queryset = Mytable.objects.all()
    pieceOfQuery = copy.copy(queryset)
    pieceOfQuery = pieceOfQuery[:10]
    
    UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now)[0:5].update(read=True)
    
    UserLog.objects.filter(user=user).filter(action='message').filter(timestamp__lt=now).update(read=True)[0:5]