crowley
crowley

Reputation: 95

Data migration to replace instances of a word in a TextField?

I am writing a data migration to go through some general templates used to send notifications with the goal of changing all instances of 'word1' to 'word2'. 'word1' can occur in both the name of the template as well as the body. Currently, there is only one template with 'word1' in the name, so I am able to change that one easily with an if statement that grabs that exact name and replaces it with the desired name. The issue I am running into is swapping 'word1' with 'word2' when it appears in the body of a template. An additional note to make is that the occurrences of 'word1' in the body are independent entirely from the occurrences in the name.

So far, I've tried using an if statement with a_notification.body.contains('word1') in my for loop to find which notifications contain that word. I've also tried splitting up the body into a list of words, splitting the textfield by space characters, and then using a for loop to check each individual word to see if it is equal to 'word1'. Currently, I am trying to use .replace() to find the instance and replace it with the desired word.

Migration file:

#Generated by Django 1.11.6 on 2019-07-08 20:05
from __future__ import unicode_literals

from django.db import migrations

def word1_to_word2(apps, schema_editor):
    notification = apps.get_model('hr', 'NotificationTemplate')
    for a_notification in notification.objects.all():
        #change the name of template that needs to be changed
        if a_notification.name == 'Name with word1':
            a_notification.name = 'Name with word2'

        #Loop through body of template and change the instances
        if 'word1' in a_notification.body in a_notification.body:
            a_notification.body.replace('word1', 'word2')
        a_notification.save()

class Migration(migrations.Migration):

    dependencies = [
        ('hr', '0013_rename_fieldA'),
    ]

    operations = [
        migrations.RunPython(word1_to_word2),
    ]

models.py

class Notification(models.Model):

    title = models.CharField(
        max_length=100, default="UREC Message", db_index=True)
    sender = models.ForeignKey(User)

    # Recepients
    employee_recepients = models.ManyToManyField(Employee, blank=True)

    # Email Pieces
    template = models.ForeignKey(NotificationTemplate, blank=True, null=True)
    signature = models.ForeignKey(NotificationSignature, blank=True, null=True)
    date_created = models.DateTimeField(auto_now_add=True)
    date_sent = models.DateTimeField(null=True)
    body = models.TextField(blank=True)

Upvotes: 1

Views: 256

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476594

The reason why this did not work is because strings are immutable. A some_string.replace(..) does not change the string, it creates a new one.

You thus can call this with:

a_notification.body = a_notification.body.replace('word1', 'word2')

That being said, this is rather inefficient, since you do a query per object. Since , you can make two bulk updates with a Replace expression [Django-doc]:

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

def word1_to_word2(apps, schema_editor):
    notification = apps.get_model('hr', 'NotificationTemplate')
    notification.objects.update(name=Replace('name', Value('word1'), Value('word2')))
    notification.objects.update(body=Replace('body', Value('word1'), Value('word2')))

Upvotes: 2

Related Questions