有效地更新同一字段多个对象django

Posted

技术标签:

【中文标题】有效地更新同一字段多个对象django【英文标题】:Efficiently update same field multiple objects django 【发布时间】:2021-08-30 07:55:18 【问题描述】:

我有一个模型,我想为多个记录发送一个将字段值增加 1 的值。 我搜索了有效的更新答案,例如Efficient way to update multiple fields of Django model object,但他们认为我有值而我想增加,因此不同记录的值可能不同。

我的模型看起来像这样:

class Signal(models.Model):
    name = models.CharField(max_length=80)
    version = models.IntegerField()

在我看来,我想发送一个名称列表,然后将其所有版本更新 1。

我目前的方法是查看名称、创建对象、更新版本和手动保存,如下所示:

    signals = Signal.objects.filter(name__in=signal_names)
    for signal in signals:
        signal.pk=None
        signal.version = signal.version+1
        signal.save()

这会导致查询过多且速度非常慢,因为我将一次发送 100 个名称。

有没有更好的方法来做到这一点?

注意:这可能看起来类似于批量更新问题,但在这种情况下,我想增加 1,所以我没有更新的值。那是我与现有答案的斗争。

例子:

信号表

name | version
n1 | 1
n2 | 2

我在我的帖子中发送 ["n1", "n2"] 并且输出应该是

信号表

name | version
n1 | 1
n2 | 2
n1 | 2
n2 | 3

更新 我发现的另一个意外情况是,下次我想更新时,我只想更新最新版本——不是全部

所以如果我再次运行 POST 请求,值应该是

信号表

name | version
n1 | 1
n2 | 2
n1 | 2
n2 | 3

n1 | 3
n2 | 4

如何过滤以仅更新每个名称的最新版本? 我使用的数据库是“sql server”

【问题讨论】:

【参考方案1】:

您可以使用.bulk_create(…) [Django-doc] 列出新信号并在数据库中批量创建这些信号:

# create new Signal objects

results = []
signals = Signal.objects.filter(name__in=signal_names)

for signal in signals:
    signal.pk = None
    signal.version += 1
    results.append(signal)

Signal.objects.bulk_create(results)

然而,这会产生重复。如果您想更新现有 Signals,那么您可以使用.update(…) [Django-doc]:

# updating the existing the Signal objects

signals = Signal.objects.filter(name__in=signal_names).update(
    version=F('version') + 1
)

如果您只想获取最新版本,则应将 signals 查询集更改为 Exists subquery [Django-doc]:

from django.db.models import Exists, OuterRef

Signal.objects.filter(
    ~Exists(Signal.objects.filter(
        name=OuterRef('name'), version__gt=OuterRef('version')
    )),
    name__in=signal_names,
)

【讨论】:

感谢您的及时答复。这减少了我的查询数量,但有没有办法避免完全循环和更清晰的代码?也许一些固有的 django 功能可以帮助我? @ShubhamPeriwal:不是在您创建 new 对象时。如果您想更新对象,那么您可以使用.update(...)。然而,循环不会进行任何查询,因此这通常会以每秒约 100k 次迭代运行,这可能就足够了。毕竟数据库也会做一些循环来更新记录,所以不会改变时间复杂度。 啊好的好的,谢谢。我不想更新现有的行。我需要为每条记录创建一个新行。我想循环是唯一的方法!让我试试看 Willem Van Onsem ~ 抱歉,我又添加了一项功能。是否可以更新您的代码以使用它?我无法最终实现它。 @ShubhamPeriwal 我觉得你的造型很糟糕。如果你想对这个模型进行某种版本控制,使用一个外键的额外模型会更好。

以上是关于有效地更新同一字段多个对象django的主要内容,如果未能解决你的问题,请参考以下文章

django,ajax:如何有效地实时更新一堆数据

如何根据记录中其他 4 个字段的布尔运算符有效地更新数据框中的字段?

我们如何使用 stl 容器有效地存储对象? (即根据字段值进行搜索)[关闭]

检测 Blender 对象中的更改以更有效地导出脚本

如何在 Blender 中有效地更改多个对象的相同参数?

创建SQL触发器以反转先前的触发器