From b5205c5d9f1b3f56d2a280bfc265d7df58461c11 Mon Sep 17 00:00:00 2001 From: Julia Eskew Date: Wed, 7 Jul 2021 15:37:54 -0400 Subject: [PATCH] fix: Add a data migration which removes any existing duplicates in the learning sequences Django app's user partition group model. fix: Add a unique constraint on that same model on partition_id/group_id to avoid future duplicates. TNL-8314 --- ..._remove_user_partition_group_duplicates.py | 47 +++++++++++++++++++ ..._user_partition_group_unique_constraint.py | 17 +++++++ .../content/learning_sequences/models.py | 3 ++ 3 files changed, 67 insertions(+) create mode 100644 openedx/core/djangoapps/content/learning_sequences/migrations/0014_remove_user_partition_group_duplicates.py create mode 100644 openedx/core/djangoapps/content/learning_sequences/migrations/0015_add_user_partition_group_unique_constraint.py diff --git a/openedx/core/djangoapps/content/learning_sequences/migrations/0014_remove_user_partition_group_duplicates.py b/openedx/core/djangoapps/content/learning_sequences/migrations/0014_remove_user_partition_group_duplicates.py new file mode 100644 index 0000000000..0469daa6ad --- /dev/null +++ b/openedx/core/djangoapps/content/learning_sequences/migrations/0014_remove_user_partition_group_duplicates.py @@ -0,0 +1,47 @@ +# Generated by Django 2.2.24 on 2021-07-07 18:34 + +from django.db import migrations +from django.db.models import Count, Min + + +class Migration(migrations.Migration): + + def remove_user_partition_group_duplicates(apps, schema_editor): + UserPartitionGroup = apps.get_model('learning_sequences', 'UserPartitionGroup') + + upg_duplicates = ( + UserPartitionGroup.objects.values("partition_id", "group_id") + .annotate(first_entry_id=Min("id"), num_entries=Count("id")) + .filter(num_entries__gt=1) + ) + + for duplicate in upg_duplicates: + + # Repoint the course sections and section sequences which have the duplicate user partition + # group entries to the single remaining non-duplicate user partition group. + upg_to_keep = UserPartitionGroup.objects.filter(id=duplicate["first_entry_id"])[:1].get() + upgs_to_remove = ( + UserPartitionGroup.objects + .filter(partition_id=duplicate["partition_id"], group_id=duplicate["group_id"]) + .exclude(id=duplicate["first_entry_id"]) + ) + for one_duplicate in upgs_to_remove: + sections_to_change = one_duplicate.coursesection_set.all() + for section in sections_to_change: + section.user_partition_groups.remove(one_duplicate) + section.user_partition_groups.add(upg_to_keep) + sequences_to_change = one_duplicate.coursesectionsequence_set.all() + for sequence in sequences_to_change: + sequence.user_partition_groups.remove(one_duplicate) + sequence.user_partition_groups.add(upg_to_keep) + + # Remove the duplicate user partition groups. + upgs_to_remove.delete() + + dependencies = [ + ('learning_sequences', '0013_through_model_for_user_partition_groups_1'), + ] + + operations = [ + migrations.RunPython(code=remove_user_partition_group_duplicates, reverse_code=migrations.RunPython.noop) + ] diff --git a/openedx/core/djangoapps/content/learning_sequences/migrations/0015_add_user_partition_group_unique_constraint.py b/openedx/core/djangoapps/content/learning_sequences/migrations/0015_add_user_partition_group_unique_constraint.py new file mode 100644 index 0000000000..414105ceb2 --- /dev/null +++ b/openedx/core/djangoapps/content/learning_sequences/migrations/0015_add_user_partition_group_unique_constraint.py @@ -0,0 +1,17 @@ +# Generated by Django 2.2.24 on 2021-07-07 19:32 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('learning_sequences', '0014_remove_user_partition_group_duplicates'), + ] + + operations = [ + migrations.AlterUniqueTogether( + name='userpartitiongroup', + unique_together={('partition_id', 'group_id')}, + ), + ] diff --git a/openedx/core/djangoapps/content/learning_sequences/models.py b/openedx/core/djangoapps/content/learning_sequences/models.py index ed7fae1f74..6674a2dcea 100644 --- a/openedx/core/djangoapps/content/learning_sequences/models.py +++ b/openedx/core/djangoapps/content/learning_sequences/models.py @@ -180,6 +180,9 @@ class UserPartitionGroup(models.Model): group_id = models.BigIntegerField(null=False) class Meta: + unique_together = [ + ['partition_id', 'group_id'], + ] indexes = [ models.Index(fields=['partition_id', 'group_id']), ]