Django批量更新并替换字符串

27

我正在尝试更新和修改Django ORM中的字符串字段。相应的SQL操作如下:

UPDATE example_table SET string_field = REPLACE(string_field, 'old text', 'new text');
使用该查询语句,我期望将“string_field”列中所有条目的“old text”和“old text more text”分别替换为“new text”和“new text more text”。Bulk update() 看起来很有前途,但不允许我仅修改字段的一部分,F()表达式 只实现数字更改,而不是字符串替换。 我还尝试使用原始查询来运行上述SQL,但那似乎是一个侧面的黑客方法(特别是由于F()存在以执行相同的数字功能),并且我无法使它们实际执行。最终我得到了这个解决方案,但当我知道可以用一行SQL语句完成时,执行所有额外的查询似乎有点可惜。
for entry in ExampleModel.objects.all():
    entry.string_field = entry.string_field.replace('old text', 'new text', 1)
    entry.save()

这个功能在Django的ORM中还不存在吗?我在文档中有没有漏看什么?

相关的Stack Overflow问题:


我曾经遇到过这个问题。我找到的最好的方法是在Python代码中进行字符串处理。如果您不介意使用原始SQL,那么replace函数在任何数据库之间都非常一致。 - Edwin Lunando
5个回答

40

测试过 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
适用于 1.8+ https://docs.djangoproject.com/en/1.8/ref/models/expressions/#func-expressions 和 PostgreSQL。 - int_ua
1
使用mysql(mariadb)在1.11版本上工作。 - Mohammed Shareef C
正在使用10.6.7-MariaDB进行开发。 - urek mazino

5
您可以创建自己的类似于F对象来表示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支持是什么? - Kevin Brown-Silva
不太确定。我只是在1.6.6上尝试了一下;我预计它应该可以在(更早的)版本中工作,但具体情况不确定。就SQL而言,“REPLACE”函数似乎以这种形式存在于至少Postgres、MySQL和SQLite中。 - Andrew Magee

3

Django 2.1的新增功能 - 替换数据库函数

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

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

1
您在 Replace 后面多了一个 ) - James

0
使用replace_field_substring(YourModel, "your_field", "value_from", "value_to")函数。
from django.db.models import F, Value, QuerySet
from django.db.models.functions import Replace

def replace_field_substring(model_or_qs, field, value_from, value_to):
    """Generates ORM partial replace, which can be used in Django ORM data migrations,
    for example for partial replace tbl.cont from="twitter.com" to="x.com" will give you
    UPDATE tbl SET cont = REPLACE(cont, 'twitter.com', 'x.com') WHERE cont LIKE '%twitter.com%';
    """
    qs = model_or_qs if isinstance(model_or_qs, QuerySet) else model_or_qs.objects.all()
    replacement_expression = Replace(F(field), Value(value_from), Value(value_to))
    qs.update(**{field: replacement_expression})

-1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接