# Generated for QI multi-department support. # # Order matters: # 1. Add the new `departments` M2M (blank). # 2. Copy each existing `department_id` into the M2M, then rebuild the derived # `team_members` set from each department's champion + manager (and the # project lead). The sync logic is inlined here (not imported from the # model) so the migration stays stable as the model method evolves. # 3. Remove the old single `department` FK. from django.db import migrations, models def copy_department_and_sync_team(apps, schema_editor): QIProject = apps.get_model("projects", "QIProject") Staff = apps.get_model("organizations", "Staff") missing_manager_profile = 0 for project in QIProject.objects.exclude(department__isnull=True): old_dept = project.department # M2M add via the through manager (project has just been saved with the new field). if old_dept and old_dept not in project.departments.all(): project.departments.add(old_dept) # Rebuild derived team_members: champion (Staff) + manager.staff_profile (Staff), # plus the project lead. De-duped; nulls skipped. pks = set() for dept in project.departments.all(): champion_id = getattr(dept, "champion_id", None) if champion_id: pks.add(champion_id) manager_user_id = getattr(dept, "manager_id", None) if manager_user_id: manager_user = dept.manager if manager_user is not None and hasattr(manager_user, "staff_profile"): sp = manager_user.staff_profile if sp is not None and sp.id: pks.add(sp.id) else: missing_manager_profile += 1 if project.project_lead_id: pks.add(project.project_lead_id) if pks: project.team_members.set(Staff.objects.filter(pk__in=pks)) if missing_manager_profile: # Surface how many manager links could not be added (no staff_profile). print(f" [qi_multi_department] {missing_manager_profile} department manager(s) " f"had no staff_profile and were excluded from the derived team.") def remove_team_backreference(apps, schema_editor): # Reverse is a no-op: we cannot reconstruct the single FK from the M2M losslessly. pass class Migration(migrations.Migration): dependencies = [ ("organizations", "0015_hospital_branding"), ("projects", "0003_alter_qiproject_project_lead_and_more"), ] operations = [ migrations.AddField( model_name="qiproject", name="departments", field=models.ManyToManyField( blank=True, help_text="Departments involved in this QI project. Team membership is derived from each department's champion and manager.", related_name="qi_projects", to="organizations.department", ), ), migrations.RunPython(copy_department_and_sync_team, remove_team_backreference), migrations.RemoveField( model_name="qiproject", name="department", ), ]