Files
dashboard-cpsp/backend/apps/farms/migrations/0017_site_slug_pk.py
T

122 lines
4.0 KiB
Python

# Convert Site.site_id from BigAutoField to name-based SlugField PK with numeric suffix.
# atomic=False: PostgreSQL cannot ALTER TABLE in the same transaction after PK UPDATEs.
from django.db import migrations, models
import django.db.models.deletion
from django.utils.text import slugify
def _unique_slug(site_name: str, old_pk: str, used: set[str]) -> str:
base = slugify(str(site_name or "").strip())[:55] or f"site-{old_pk}"[:55]
try:
seed = int(old_pk) % 10000
except ValueError:
seed = sum(ord(c) for c in old_pk) % 10000
for i in range(10000):
code = f"{base}-{(seed + i) % 10000:04d}"
if code not in used:
used.add(code)
return code
raise RuntimeError(f"Could not allocate site id for {old_pk}")
def forwards_slug_pks(apps, schema_editor):
Site = apps.get_model("farms", "Site")
Kandang = apps.get_model("farms", "Kandang")
PusatRegistration = apps.get_model("farms", "PusatRegistration")
used: set[str] = set()
mapping: dict[str, str] = {}
for site in Site.objects.all().order_by("site_id"):
old = str(site.site_id)
mapping[old] = _unique_slug(site.site_name, old, used)
for old_id, new_id in mapping.items():
if old_id == new_id:
continue
Kandang.objects.filter(site_id=old_id).update(site_id=new_id)
PusatRegistration.objects.filter(site_id=old_id).update(site_id=new_id)
Site.objects.filter(site_id=old_id).update(site_id=new_id)
# Ensure site names are unique before adding the constraint.
seen_names: dict[str, int] = {}
for site in Site.objects.all().order_by("site_id"):
name = site.site_name
count = seen_names.get(name, 0)
seen_names[name] = count + 1
if count == 0:
continue
suffix = f"-{count + 1}"
site.site_name = f"{name[: 30 - len(suffix)]}{suffix}"
site.save(update_fields=["site_name"])
def noop_reverse(apps, schema_editor):
raise RuntimeError("Cannot reverse site_id slug migration.")
class Migration(migrations.Migration):
atomic = False
dependencies = [
("farms", "0016_pusat_registration"),
]
operations = [
migrations.AlterField(
model_name="kandang",
name="site",
field=models.ForeignKey(
db_constraint=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="kandangs",
to="farms.site",
),
),
migrations.AlterField(
model_name="pusatregistration",
name="site",
field=models.OneToOneField(
db_constraint=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="pusat_registration",
to="farms.site",
),
),
migrations.AlterField(
model_name="site",
name="site_id",
field=models.CharField(max_length=64, primary_key=True, serialize=False),
),
migrations.RunPython(forwards_slug_pks, noop_reverse),
migrations.AlterField(
model_name="site",
name="site_id",
field=models.SlugField(max_length=64, primary_key=True, serialize=False),
),
migrations.AlterField(
model_name="site",
name="site_name",
field=models.CharField(max_length=30, unique=True),
),
migrations.AlterField(
model_name="kandang",
name="site",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="kandangs",
to="farms.site",
),
),
migrations.AlterField(
model_name="pusatregistration",
name="site",
field=models.OneToOneField(
on_delete=django.db.models.deletion.CASCADE,
related_name="pusat_registration",
to="farms.site",
),
),
]