【问题标题】:Duplicate django query set?重复的django查询集?
【发布时间】:2009-07-23 07:37:58
【问题描述】:

我有一个简单的 django 查询集,例如:

qs = AModel.objects.exclude(state="F").order_by("order")

我想按如下方式使用它:

qs[0:3].update(state='F')
expected = qs[3] # throws error here

但最后一条语句抛出: “一旦获取切片,就无法更新查询。”

如何复制查询集?

【问题讨论】:

    标签: python django django-models


    【解决方案1】:

    这是引发错误的第一行:你不能执行 qs[0:3].update()。 qs[0:3] 正在切片; update() 正在更新查询。

    update() 用于批量更新,产生类似的 SQL 查询

    UPDATE app_model SET state = 'F' WHERE state <> 'F';
    

    您正在尝试根据“顺序”更新前三个项目,但是使用这种类型的 UPDATE 无法做到这一点——您无法订购或限制 SQL UPDATE。它需要以不同的方式编写,例如。

    UPDATE app_model SET state = 'F' WHERE id IN (
        SELECT id FROM app_model WHERE state <> 'F' ORDER BY order LIMIT 3
    ) AS sub;
    

    但 Django 不能为你做到这一点。

    【讨论】:

      【解决方案2】:

      你可以这样做:

      qs = AModel.objects.filter(id__in= AModel.objects.exclude(state="F").order_by("order")[10]).update()

      【讨论】:

        【解决方案3】:

        之前有一些关于使查询集切片成为可能,然后能够在它们上使用更新的讨论,但是 AFAIK 从来没有做过任何事情。我认为您不能复制查询集的一部分,但在这种情况下您不需要这样做。如果您的订单是唯一整数,您可以这样做:

        qs = AModel.objects.exclude(state="F").order_by("order")
        if len(qs) > 3:
            slice = qs.exclude(order__gt=qs[3])
        else:
            slice = qs
        slice.update(state='F')
        

        我使用排除来删除不需要的元素,但这仅在订单唯一的情况下才有效,否则您将无法知道您更新了多少。如果 order 不是唯一的,仍然可以按顺序使用第二个唯一的 arg:

        qs = AModel.objects.exclude(state="F").order_by("order", "pk")
        if len(qs) > 3:
            slice = qs.exclude(order__gt=qs[3]).exclude(order=qs[3], pk__gt=qs[3])
        ...
        

        【讨论】:

        • 请注意,这是非原子的,即使在事务中(至少在 Postgres 中),除非您先取出表锁。
        • 您可以使用 qs.all() 复制查询集,但这对您没有帮助。
        • 我的意思是复制 QuerySet 的一部分来创建一个可以运行更新的新的。明确的答案。
        猜你喜欢
        • 2016-09-30
        • 2017-05-02
        • 2017-04-12
        • 1970-01-01
        • 1970-01-01
        • 2013-04-25
        • 2015-09-26
        • 1970-01-01
        相关资源
        最近更新 更多