2014-01-30 80 views
14

我想更新和修改字符串字段Django的ORM。等效SQL要做到這一點:Django批量更新字符串替換

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

隨着該查詢,我希望old textold text more textnew textnew text more text分別被替換,在string_field列中的所有條目。

Bulk update()似乎很有前途,但不允許我只修改部分字段,而F() expressions只實現數字更改,而不是字符串替換。我還着眼於使用raw queries來運行上面的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字符串中不存在此功能嗎?有沒有我在文檔中忽略的東西?

SO相關的問題:

+0

我也碰到這個問題回到那裏。我能找到的最好的方法是在Python代碼中進行字符串處理。如果您不介意使用原始SQL,則任何數據庫之間的替換函數都是非常一致的。 –

回答

4

你可以使自己的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對象不無論如何,似乎都可以使用字符串。

+0

任何想法Django版本和DBMS支持這是什麼? –

+0

不確定。我剛剛在1.6.6上試了一下;我預計它可以在(很多)早期版本中工作,但不確定具體情況。在SQL方面,'REPLACE'函數似乎至少以Postgres,MySQL和SQLite的形式存在。 –

8

測試和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', 
    ) 
) 
+1

工作於**'1.8 +'** https://docs.djangoproject.com/en/1.8/ref/models/expressions/#func-expressions和PostgreSQL –

+1

已確認與django合作1.11.2 – user1330734