122 lines
4.0 KiB
Python
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",
|
|
),
|
|
),
|
|
]
|