fix: Use a "through" model for the ManyToManyField fields in CourseSection
and CourseSectionSequence to ensure that cascading deletes will occur to delete the relation upon deletion of a foreign-keyed object. This commit is phase 1 of 3 in order to ensure a smooth deploy. The phases: 1) Add separate through models for user partition groups, add fields to point to the separate models, and start writing to those fields as well. 2) After all models have been re-generated, switch code over to use separate through model fields backed by the separate through models. 3) After phase 2 is deployed smoothly, remove the original ManyToManyField fields and rename the new fields to have the same name as the old fields.
This commit is contained in:
@@ -561,6 +561,17 @@ def _update_user_partition_groups(upg_data: Dict[int, FrozenSet[int]],
|
||||
)
|
||||
model_obj.user_partition_groups.add(upg)
|
||||
|
||||
# Temporarily fill-in the new and old user_partition_group fields.
|
||||
# Switchover to the new field will occur after all models have been repopulated.
|
||||
model_obj.new_user_partition_groups.all().delete()
|
||||
if upg_data:
|
||||
for partition_id, group_ids in upg_data.items():
|
||||
for group_id in group_ids:
|
||||
upg, _ = UserPartitionGroup.objects.get_or_create(
|
||||
partition_id=partition_id, group_id=group_id
|
||||
)
|
||||
model_obj.new_user_partition_groups.add(upg)
|
||||
|
||||
|
||||
def _update_publish_report(course_outline: CourseOutlineData,
|
||||
content_errors: List[ContentErrorData],
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
# Generated by Django 2.2.24 on 2021-06-14 22:04
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('learning_sequences', '0012_add_user_partition_group'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='SectionSequencePartitionGroup',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('course_section_sequence', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='learning_sequences.CourseSectionSequence')),
|
||||
('user_partition_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='learning_sequences.UserPartitionGroup')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('user_partition_group', 'course_section_sequence')},
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='SectionPartitionGroup',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('course_section', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='learning_sequences.CourseSection')),
|
||||
('user_partition_group', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='learning_sequences.UserPartitionGroup')),
|
||||
],
|
||||
options={
|
||||
'unique_together': {('user_partition_group', 'course_section')},
|
||||
},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='coursesection',
|
||||
name='new_user_partition_groups',
|
||||
field=models.ManyToManyField(db_index=True, related_name='sec_user_partition_groups', related_query_name='sec_user_partition_group', through='learning_sequences.SectionPartitionGroup', to='learning_sequences.UserPartitionGroup'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='coursesectionsequence',
|
||||
name='new_user_partition_groups',
|
||||
field=models.ManyToManyField(db_index=True, related_name='secseq_user_partition_groups', related_query_name='secseq_user_partition_group', through='learning_sequences.SectionSequencePartitionGroup', to='learning_sequences.UserPartitionGroup'),
|
||||
),
|
||||
]
|
||||
@@ -201,6 +201,14 @@ class CourseSection(CourseContentVisibilityMixin, TimeStampedModel):
|
||||
|
||||
user_partition_groups = models.ManyToManyField(UserPartitionGroup)
|
||||
|
||||
new_user_partition_groups = models.ManyToManyField(
|
||||
UserPartitionGroup,
|
||||
db_index=True,
|
||||
related_name='sec_user_partition_groups',
|
||||
related_query_name='sec_user_partition_group',
|
||||
through='SectionPartitionGroup'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
unique_together = [
|
||||
['course_context', 'usage_key'],
|
||||
@@ -210,6 +218,22 @@ class CourseSection(CourseContentVisibilityMixin, TimeStampedModel):
|
||||
]
|
||||
|
||||
|
||||
class SectionPartitionGroup(models.Model):
|
||||
"""
|
||||
Model which maps user partition groups to course sections.
|
||||
Used for the user_partition_groups ManyToManyField field in the CourseSection model above.
|
||||
Adds a cascading delete which will delete these many-to-many relations
|
||||
whenever a UserPartitionGroup or CourseSection object is deleted.
|
||||
"""
|
||||
class Meta:
|
||||
unique_together = [
|
||||
['user_partition_group', 'course_section'],
|
||||
]
|
||||
|
||||
user_partition_group = models.ForeignKey(UserPartitionGroup, on_delete=models.CASCADE)
|
||||
course_section = models.ForeignKey(CourseSection, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class CourseSectionSequence(CourseContentVisibilityMixin, TimeStampedModel):
|
||||
"""
|
||||
This is a join+ordering table, with entries that could get wiped out and
|
||||
@@ -241,6 +265,14 @@ class CourseSectionSequence(CourseContentVisibilityMixin, TimeStampedModel):
|
||||
|
||||
user_partition_groups = models.ManyToManyField(UserPartitionGroup)
|
||||
|
||||
new_user_partition_groups = models.ManyToManyField(
|
||||
UserPartitionGroup,
|
||||
db_index=True,
|
||||
related_name='secseq_user_partition_groups',
|
||||
related_query_name='secseq_user_partition_group',
|
||||
through='SectionSequencePartitionGroup'
|
||||
)
|
||||
|
||||
class Meta:
|
||||
unique_together = [
|
||||
['course_context', 'ordering'],
|
||||
@@ -252,6 +284,22 @@ class CourseSectionSequence(CourseContentVisibilityMixin, TimeStampedModel):
|
||||
return f"{self.section.title} > {self.sequence.title}"
|
||||
|
||||
|
||||
class SectionSequencePartitionGroup(models.Model):
|
||||
"""
|
||||
Model which maps user partition groups to course section sequences.
|
||||
Used for the user_partition_groups ManyToManyField field in the CourseSectionSequence model above.
|
||||
Adds a cascading delete which will delete these many-to-many relations
|
||||
whenever a UserPartitionGroup or CourseSectionSequence object is deleted.
|
||||
"""
|
||||
class Meta:
|
||||
unique_together = [
|
||||
['user_partition_group', 'course_section_sequence'],
|
||||
]
|
||||
|
||||
user_partition_group = models.ForeignKey(UserPartitionGroup, on_delete=models.CASCADE)
|
||||
course_section_sequence = models.ForeignKey(CourseSectionSequence, on_delete=models.CASCADE)
|
||||
|
||||
|
||||
class CourseSequenceExam(TimeStampedModel):
|
||||
"""
|
||||
This model stores XBlock information that affects outline level information
|
||||
|
||||
Reference in New Issue
Block a user