187 lines
6.6 KiB
Python
187 lines
6.6 KiB
Python
from collections import defaultdict
|
|
|
|
import django.db.models.deletion
|
|
from django.db import migrations, models
|
|
|
|
|
|
def backfill_calendar_bindings(apps, schema_editor):
|
|
Calendar = apps.get_model("schedule", "Calendar")
|
|
CalendarBinding = apps.get_model("scheduling", "CalendarBinding")
|
|
ContentType = apps.get_model("contenttypes", "ContentType")
|
|
Department = apps.get_model("employees", "Department")
|
|
|
|
department_ct, _ = ContentType.objects.get_or_create(
|
|
app_label="employees",
|
|
model="department",
|
|
)
|
|
department_ids = set(Department.objects.values_list("id", flat=True))
|
|
|
|
table_names = set(schema_editor.connection.introspection.table_names())
|
|
legacy_department_map = {}
|
|
if "calendar_app_calendar" in table_names:
|
|
with schema_editor.connection.cursor() as cursor:
|
|
cursor.execute(
|
|
"""
|
|
SELECT id, owner_department_id
|
|
FROM calendar_app_calendar
|
|
WHERE owner_department_id IS NOT NULL
|
|
"""
|
|
)
|
|
legacy_department_map = {
|
|
old_id: department_id
|
|
for old_id, department_id in cursor.fetchall()
|
|
if department_id in department_ids
|
|
}
|
|
|
|
candidates = defaultdict(list)
|
|
for calendar in Calendar.objects.all().order_by("-id"):
|
|
slug = calendar.slug or ""
|
|
department_id = None
|
|
priority = None
|
|
|
|
if slug.startswith("legacy-calendar-"):
|
|
try:
|
|
legacy_id = int(slug.removeprefix("legacy-calendar-"))
|
|
except ValueError:
|
|
legacy_id = None
|
|
if legacy_id is not None:
|
|
department_id = legacy_department_map.get(legacy_id)
|
|
priority = 0 if department_id is not None else None
|
|
elif slug.startswith("department-"):
|
|
tail = slug.removeprefix("department-")
|
|
if tail.isdigit():
|
|
department_id = int(tail)
|
|
if department_id in department_ids:
|
|
priority = 1
|
|
|
|
if department_id is None or priority is None:
|
|
continue
|
|
|
|
candidates[department_id].append((priority, calendar.id))
|
|
|
|
for department_id, rows in candidates.items():
|
|
priority, calendar_id = sorted(rows, key=lambda item: (item[0], -item[1]))[0]
|
|
CalendarBinding.objects.get_or_create(
|
|
calendar_id=calendar_id,
|
|
defaults={
|
|
"type": "department",
|
|
"context_content_type_id": department_ct.id,
|
|
"context_object_id": department_id,
|
|
},
|
|
)
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
dependencies = [
|
|
("contenttypes", "0002_remove_content_type_name"),
|
|
("employees", "0047_alter_departmentpermission_code"),
|
|
("schedule", "0015_rename_indexes"),
|
|
("scheduling", "0001_initial"),
|
|
]
|
|
|
|
operations = [
|
|
migrations.CreateModel(
|
|
name="CalendarBinding",
|
|
fields=[
|
|
(
|
|
"id",
|
|
models.BigAutoField(
|
|
auto_created=True,
|
|
primary_key=True,
|
|
serialize=False,
|
|
verbose_name="ID",
|
|
),
|
|
),
|
|
(
|
|
"type",
|
|
models.CharField(
|
|
choices=[
|
|
("default", "Обычный"),
|
|
("department", "Отдел"),
|
|
],
|
|
db_index=True,
|
|
default="default",
|
|
max_length=32,
|
|
verbose_name="Тип привязки",
|
|
),
|
|
),
|
|
(
|
|
"context_object_id",
|
|
models.PositiveIntegerField(
|
|
blank=True,
|
|
null=True,
|
|
verbose_name="ID объекта контекста",
|
|
),
|
|
),
|
|
(
|
|
"flags",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=dict,
|
|
verbose_name="Флаги",
|
|
),
|
|
),
|
|
(
|
|
"extra_data",
|
|
models.JSONField(
|
|
blank=True,
|
|
default=dict,
|
|
verbose_name="Доп. данные",
|
|
),
|
|
),
|
|
("created_at", models.DateTimeField(auto_now_add=True)),
|
|
("updated_at", models.DateTimeField(auto_now=True)),
|
|
(
|
|
"calendar",
|
|
models.OneToOneField(
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
related_name="binding",
|
|
to="schedule.calendar",
|
|
verbose_name="Календарь",
|
|
),
|
|
),
|
|
(
|
|
"context_content_type",
|
|
models.ForeignKey(
|
|
blank=True,
|
|
null=True,
|
|
on_delete=django.db.models.deletion.CASCADE,
|
|
to="contenttypes.contenttype",
|
|
verbose_name="Тип контекста",
|
|
),
|
|
),
|
|
],
|
|
options={
|
|
"verbose_name": "Привязка календаря",
|
|
"verbose_name_plural": "Привязки календарей",
|
|
},
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="calendarbinding",
|
|
index=models.Index(fields=["type"], name="calendar_binding_type_idx"),
|
|
),
|
|
migrations.AddIndex(
|
|
model_name="calendarbinding",
|
|
index=models.Index(
|
|
fields=["context_content_type", "context_object_id"],
|
|
name="calendar_binding_context_idx",
|
|
),
|
|
),
|
|
migrations.AddConstraint(
|
|
model_name="calendarbinding",
|
|
constraint=models.UniqueConstraint(
|
|
condition=models.Q(
|
|
("context_content_type__isnull", False),
|
|
("context_object_id__isnull", False),
|
|
("type", "department"),
|
|
),
|
|
fields=("type", "context_content_type", "context_object_id"),
|
|
name="uniq_department_calendar_binding",
|
|
),
|
|
),
|
|
migrations.RunPython(
|
|
backfill_calendar_bindings,
|
|
migrations.RunPython.noop,
|
|
),
|
|
]
|