【问题标题】:Django bulk update with string replace使用字符串替换的 Django 批量更新
【发布时间】:2014-02-23 06:04:50
【问题描述】:

我正在尝试更新和修改 Django 的 ORM 字符串字段。执行此操作的等效 SQL 是:

UPDATE example_table SET string_field = REPLACE(string_field, 'old text', 'new text');

通过该查询,对于string_field 列中的所有条目,我希望old textold text more text 分别替换为new textnew text more text

Bulk update() 看起来很有希望,但不允许我只修改部分字段,F() expressions 只实现数字更改,而不是字符串替换。我还研究了使用raw queries 来运行上面的 SQL,但这似乎是一个横向的 hack(特别是因为 F() 存在对数字执行相同的功能),我无法让它们实际执行。

我最终得到了这个,但是当我知道有一条 SQL 语句可以执行时,执行所有额外的查询似乎很可惜。

for entry in ExampleModel.objects.all():
    entry.string_field = entry.string_field.replace('old text', 'new text', 1)
    entry.save()

在 Django 的字符串 ORM 中还没有这个功能吗?我在文档中忽略了什么?

相关的 SO 问题:

【问题讨论】:

  • 我把这个问题带回来了。我能找到的最好方法是在 Python 代码中进行字符串处理。如果您不介意使用原始 SQL,则替换功能在任何数据库之间都非常一致。

标签: python django django-orm


【解决方案1】:

使用 django 1.9 测试

from django.db.models import F, Func, Value

ExampleModel.objects.filter(<condition>).update(
    string_field=Func(
        F('string_field'),
        Value('old text'), Value('new text'),
        function='replace',
    )
)

更新 Django 2.1 https://docs.djangoproject.com/en/2.2/ref/models/database-functions/#replace

from django.db.models import Value
from django.db.models.functions import Replace

ExampleModel.objects.filter(<condition>).update(
    string_field=Replace('string_field', Value('old text'), Value('new text'))
)

【讨论】:

【解决方案2】:

您可以创建自己的F-like 对象来表示 SQL 中的字符串替换。这是一个概念证明:

from django.db.models.expressions import ExpressionNode

class StringReplaceF(ExpressionNode):
    def __init__(self, field, replace_from, replace_to):
        self.field = field
        self.replace_from = replace_from
        self.replace_to = replace_to
        super(StringReplaceF, self).__init__()

    def evaluate(self, evaluator, qn, connection):
        return (
            "REPLACE({}, %s, %s)".format(self.field),
            (self.replace_from, self.replace_to)
        )

 >>> f = StringReplaceF('string_field', 'old text', 'new text')
 >>> ExampleModel.objects.update(string_field=f)

如果您需要该类与其他 F 对象表现良好,则需要对该类做更多的工作,但话说回来,现有的 F 对象似乎无论如何都不适用于字符串。

【讨论】:

  • 知道 Django 版本和 DBMS 对此的支持是什么吗?
  • 不确定。我刚刚在 1.6.6 上尝试过;我希望它可以在(很多)早期版本中使用,但不确定具体细节。在 SQL 方面,REPLACE 函数似乎至少在 Postgres、MySQL 和 SQLite 中以这种形式存在。
【解决方案3】:

Django 2.1 中的新功能 - Replace database function

您的示例现在可以通过以下方式最轻松地表达:

ExampleModel.objects.update(
    string_field=Replace('string_field', Value('old_text'), Value('new_text'))
)

【讨论】:

  • 你在Replace之后有额外的)
【解决方案4】:

Django 2.2支持批量更新,你能用那个功能吗?

检查这个:https://docs.djangoproject.com/en/2.2/ref/models/querysets/#django.db.models.query.QuerySet.bulk_create

【讨论】:

    猜你喜欢
    • 2011-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2014-07-29
    • 2015-07-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多