import uuid import django.db.models.deletion from django.db import migrations, models def backfill_devices_from_sensor_payload(apps, schema_editor): SensorData = apps.get_model("sensor_data", "SensorData") Device = apps.get_model("sensor_data", "Device") for farm in SensorData.objects.all().iterator(): sensor_payload = farm.sensor_payload if isinstance(farm.sensor_payload, dict) else {} location_id = getattr(farm, "center_location_id", None) if location_id is None: continue for sensor_name, payload in sensor_payload.items(): if not isinstance(payload, dict): continue cluster_uuid = None raw_cluster_uuid = payload.get("cluster_uuid") if raw_cluster_uuid not in (None, ""): try: cluster_uuid = uuid.UUID(str(raw_cluster_uuid)) except (TypeError, ValueError, AttributeError): cluster_uuid = None Device.objects.update_or_create( farm_id=farm.pk, sensor_name=sensor_name, defaults={ "location_id": location_id, "payload": payload, "cluster_uuid": cluster_uuid, }, ) class Migration(migrations.Migration): dependencies = [ ("location_data", "0019_cluster_block_centers"), ("sensor_data", "0012_plant_catalog_snapshot_and_assignment"), ] operations = [ migrations.CreateModel( name="Device", fields=[ ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), ("sensor_name", models.CharField(db_index=True, help_text='نام سنسور مثل "sensor-7-1"', max_length=64)), ("payload", models.JSONField(blank=True, default=dict, help_text="payload همان سنسور")), ("cluster_uuid", models.UUIDField(blank=True, db_index=True, help_text="uuid کلاستر داخل location برای این سنسور", null=True)), ("created_at", models.DateTimeField(auto_now_add=True)), ("updated_at", models.DateTimeField(auto_now=True)), ("farm", models.ForeignKey(db_column="farm_uuid", on_delete=django.db.models.deletion.CASCADE, related_name="devices", to="sensor_data.sensordata")), ("location", models.ForeignKey(db_column="location_id", help_text="location مرتبط با این device", on_delete=django.db.models.deletion.CASCADE, related_name="devices", to="location_data.soillocation")), ], options={ "verbose_name": "device", "verbose_name_plural": "devices", "db_table": "farm_data_device", "ordering": ["sensor_name", "id"], }, ), migrations.AddConstraint( model_name="device", constraint=models.UniqueConstraint(fields=("farm", "sensor_name"), name="farm_data_unique_device_per_farm_sensor"), ), migrations.RunPython( backfill_devices_from_sensor_payload, migrations.RunPython.noop, ), ]