Add command to bulk move user language prefs from one code to another

This commit is contained in:
bmedx
2017-12-06 12:48:05 -05:00
parent 98b391a278
commit 6294baf456

View File

@@ -0,0 +1,101 @@
"""
Migrates user preferences from one language code to another in batches. Dark lang preferences are not affected.
"""
from __future__ import print_function
import logging
from time import sleep
from django.conf import settings
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.db.models import Q, Max
from openedx.core.djangoapps.dark_lang.models import DarkLangConfig
from openedx.core.djangoapps.user_api.models import UserPreference
DEFAULT_CHUNK_SIZE = 10000
DEFAULT_SLEEP_TIME_SECS = 10
LOGGER = logging.getLogger(__name__)
class Command(BaseCommand):
"""
Implementation of the migrate command
"""
help = 'Migrate all user language preferences (excluding dark languages) from one language code to another.'
def add_arguments(self, parser):
parser.add_argument('old_lang_code',
help='Original language code, ex. "zh-cn"')
parser.add_argument('new_lang_code',
help='New language code, ex. "zh-hans"')
parser.add_argument('--start_id',
type=int,
default=1,
help='ID to begin from, in case a run needs to be restarted from the middle.')
parser.add_argument('--chunk_size',
type=int,
default=DEFAULT_CHUNK_SIZE,
help='Number of users whose preferences will be updated per batch.')
parser.add_argument('--sleep_time_secs',
type=int,
default=DEFAULT_SLEEP_TIME_SECS,
help='Number of seconds to sleep between batches.')
def handle(self, *args, **options):
"""
Execute the command.
"""
old_lang_code = options['old_lang_code']
new_lang_code = options['new_lang_code']
chunk_size = options['chunk_size']
sleep_time_secs = options['sleep_time_secs']
start = options['start_id']
end = start + chunk_size
# Make sure we're changing to a code that actually exists. Presumably it's safe to move away from a code that
# doesn't.
langs = [lang_code[0] for lang_code in settings.LANGUAGES]
langs += DarkLangConfig.current().released_languages_list
if new_lang_code not in langs:
raise CommandError('{} is not a configured language code in settings.LANGUAGES '
'or the current DarkLangConfig.'.format(new_lang_code))
max_id = UserPreference.objects.all().aggregate(Max('id'))['id__max']
print('Updating user language preferences from {} to {}. '
'Start id is {}, current max id is {}. '
'Chunk size is of {}'.format(old_lang_code, new_lang_code, start, max_id, chunk_size))
updated_count = 0
while True:
# On the last time through catch any new rows added since this run began
if end >= max_id:
print('Last round, includes all new rows added since this run started.')
id_query = Q(id__gte=start)
else:
id_query = Q(id__gte=start) & Q(id__lt=end)
curr = UserPreference.objects.filter(
id_query,
key='pref-lang',
value=old_lang_code
).update(value=new_lang_code)
updated_count += curr
print('Updated rows {} to {}, {} rows affected'.format(start, end - 1, curr))
if end >= max_id:
break
start = end
end += chunk_size
sleep(sleep_time_secs)
print('Finished! Updated {} total preferences from {} to {}'.format(updated_count, old_lang_code, new_lang_code))