loko/loko/assets/management/commands/sync_asset_parent_data.py

379 lines
19 KiB
Python

import logging
from django.core.management.base import BaseCommand
from django.db import transaction
from assets.models.trafficlights import (
TrafficLightLantern,
TrafficLightAccessory,
TrafficLightDetector,
TrafficLightControllerHardware,
TrafficLightNetworkHardware,
TrafficLightVoltageHardware,
TrafficLightElectricalCabinetContent,
)
from assets.models.sign import SignPanel
from assets.models.publiclighting import PublicLightingLightFixture
from assets.models.its import ITSGeoAsset
from assets.models.structures import StructureGeoAsset
from assets.models.buildings import BuildingAsset
from assets.models.outdoor import OutdoorAsset
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = "Synchronizes coordinates (geom, lon, lat, geojson) and locations from parent supports to child assets."
def add_arguments(self, parser):
parser.add_argument(
'--batch-size',
type=int,
default=1000,
help="Batch size for processing records."
)
def handle(self, *args, **options):
batch_size = options['batch_size']
self.stdout.write(self.style.NOTICE("Starting parent-child asset data synchronization..."))
# 1. Traffic Light Lanterns
self.stdout.write("1. Syncing Traffic Light Lanterns...")
lanterns = TrafficLightLantern.objects.select_related('pole').filter(pole__geom__isnull=False)
count = 0
to_update = []
for lantern in lanterns.iterator(chunk_size=batch_size):
if lantern.pole and lantern.pole.geom:
if lantern.geom != lantern.pole.geom or lantern.lon != lantern.pole.lon or lantern.lat != lantern.pole.lat:
lantern.geom = lantern.pole.geom
lantern.lon = lantern.pole.lon
lantern.lat = lantern.pole.lat
lantern.geojson = lantern.pole.geojson
to_update.append(lantern)
count += 1
if len(to_update) >= batch_size:
TrafficLightLantern.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson'])
to_update = []
if to_update:
TrafficLightLantern.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Traffic Light Lanterns"))
# 2. Traffic Light Accessories
self.stdout.write("2. Syncing Traffic Light Accessories...")
accessories = TrafficLightAccessory.objects.select_related('pole', 'intersection').filter(pole__geom__isnull=False)
count = 0
to_update = []
for acc in accessories.iterator(chunk_size=batch_size):
changed = False
if acc.pole and acc.pole.geom:
if acc.geom != acc.pole.geom or acc.lon != acc.pole.lon or acc.lat != acc.pole.lat:
acc.geom = acc.pole.geom
acc.lon = acc.pole.lon
acc.lat = acc.pole.lat
acc.geojson = acc.pole.geojson
changed = True
if acc.pole and acc.pole.intersection and not acc.intersection_id:
acc.intersection = acc.pole.intersection
changed = True
if changed:
to_update.append(acc)
count += 1
if len(to_update) >= batch_size:
TrafficLightAccessory.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'intersection'])
to_update = []
if to_update:
TrafficLightAccessory.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'intersection'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Traffic Light Accessories"))
# 3. Traffic Light Detectors
self.stdout.write("3. Syncing Traffic Light Detectors...")
detectors = TrafficLightDetector.objects.select_related('pole', 'controller')
count = 0
to_update = []
for det in detectors.iterator(chunk_size=batch_size):
changed = False
support = det.pole or det.controller
if support and getattr(support, 'geom', None):
if det.geom != support.geom or det.lon != support.lon or det.lat != support.lat:
det.geom = support.geom
det.lon = support.lon
det.lat = support.lat
det.geojson = support.geojson
changed = True
if det.pole and det.pole.intersection and not det.intersection_id:
det.intersection = det.pole.intersection
changed = True
elif det.controller and det.controller.intersection and not det.intersection_id:
det.intersection = det.controller.intersection
changed = True
if changed:
to_update.append(det)
count += 1
if len(to_update) >= batch_size:
TrafficLightDetector.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'intersection'])
to_update = []
if to_update:
TrafficLightDetector.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'intersection'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Traffic Light Detectors"))
# 4. Traffic Light Controller Hardware
self.stdout.write("4. Syncing Traffic Light Controller Hardware...")
hws = TrafficLightControllerHardware.objects.select_related('controller').filter(controller__geom__isnull=False)
count = 0
to_update = []
for hw in hws.iterator(chunk_size=batch_size):
if hw.controller and hw.controller.geom:
if hw.geom != hw.controller.geom or hw.lon != hw.controller.lon or hw.lat != hw.controller.lat:
hw.geom = hw.controller.geom
hw.lon = hw.controller.lon
hw.lat = hw.controller.lat
hw.geojson = hw.controller.geojson
to_update.append(hw)
count += 1
if len(to_update) >= batch_size:
TrafficLightControllerHardware.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson'])
to_update = []
if to_update:
TrafficLightControllerHardware.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Traffic Light Controller Hardwares"))
# 5. Traffic Light Network Hardware
self.stdout.write("5. Syncing Traffic Light Network Hardware...")
nets = TrafficLightNetworkHardware.objects.select_related('controller').filter(controller__geom__isnull=False)
count = 0
to_update = []
for net in nets.iterator(chunk_size=batch_size):
changed = False
if net.controller and net.controller.geom:
if net.geom != net.controller.geom or net.lon != net.controller.lon or net.lat != net.controller.lat:
net.geom = net.controller.geom
net.lon = net.controller.lon
net.lat = net.controller.lat
net.geojson = net.controller.geojson
changed = True
if net.controller and net.controller.intersection and not net.intersection_id:
net.intersection = net.controller.intersection
changed = True
if changed:
to_update.append(net)
count += 1
if len(to_update) >= batch_size:
TrafficLightNetworkHardware.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'intersection'])
to_update = []
if to_update:
TrafficLightNetworkHardware.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'intersection'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Traffic Light Network Hardwares"))
# 6. Traffic Light Voltage Hardware
self.stdout.write("6. Syncing Traffic Light Voltage Hardware...")
volts = TrafficLightVoltageHardware.objects.select_related('controller').filter(controller__geom__isnull=False)
count = 0
to_update = []
for volt in volts.iterator(chunk_size=batch_size):
changed = False
if volt.controller and volt.controller.geom:
if volt.geom != volt.controller.geom or volt.lon != volt.controller.lon or volt.lat != volt.controller.lat:
volt.geom = volt.controller.geom
volt.lon = volt.controller.lon
volt.lat = volt.controller.lat
volt.geojson = volt.controller.geojson
changed = True
if volt.controller and volt.controller.intersection and not volt.intersection_id:
volt.intersection = volt.controller.intersection
changed = True
if changed:
to_update.append(volt)
count += 1
if len(to_update) >= batch_size:
TrafficLightVoltageHardware.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'intersection'])
to_update = []
if to_update:
TrafficLightVoltageHardware.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'intersection'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Traffic Light Voltage Hardwares"))
# 7. Traffic Light Electrical Cabinet Contents
self.stdout.write("7. Syncing Traffic Light Electrical Cabinet Contents...")
contents = TrafficLightElectricalCabinetContent.objects.select_related('cabinet').filter(cabinet__geom__isnull=False)
count = 0
to_update = []
for content in contents.iterator(chunk_size=batch_size):
if content.cabinet and content.cabinet.geom:
if content.geom != content.cabinet.geom or content.lon != content.cabinet.lon or content.lat != content.cabinet.lat:
content.geom = content.cabinet.geom
content.lon = content.cabinet.lon
content.lat = content.cabinet.lat
content.geojson = content.cabinet.geojson
to_update.append(content)
count += 1
if len(to_update) >= batch_size:
TrafficLightElectricalCabinetContent.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson'])
to_update = []
if to_update:
TrafficLightElectricalCabinetContent.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Electrical Cabinet Contents"))
# 8. Road Sign Panels
self.stdout.write("8. Syncing Road Sign Panels...")
panels = SignPanel.objects.select_related('pole', 'trafficlight_pole', 'publiclighting_pole')
count = 0
to_update = []
for panel in panels.iterator(chunk_size=batch_size):
changed = False
support = panel.pole or panel.trafficlight_pole or panel.publiclighting_pole
if support and getattr(support, 'geom', None):
if panel.geom != support.geom or panel.lon != support.lon or panel.lat != support.lat:
panel.geom = support.geom
panel.lon = support.lon
panel.lat = support.lat
panel.geojson = support.geojson
changed = True
if panel.pole and panel.pole.street and not panel.street_id:
panel.street = panel.pole.street
changed = True
if changed:
to_update.append(panel)
count += 1
if len(to_update) >= batch_size:
SignPanel.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'street'])
to_update = []
if to_update:
SignPanel.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'street'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Road Sign Panels"))
# 9. Public Lighting Light Fixtures (Luminaires)
self.stdout.write("9. Syncing Public Lighting Light Fixtures...")
fixtures = PublicLightingLightFixture.objects.select_related('pole', 'traffic_light_pole')
count = 0
to_update = []
for fix in fixtures.iterator(chunk_size=batch_size):
changed = False
support = fix.pole or fix.traffic_light_pole
if support and getattr(support, 'geom', None):
if fix.geom != support.geom or fix.lon != support.lon or fix.lat != support.lat:
fix.geom = support.geom
fix.lon = support.lon
fix.lat = support.lat
fix.geojson = support.geojson
changed = True
if fix.pole and fix.pole.street and not fix.street_id:
fix.street = fix.pole.street
changed = True
if changed:
to_update.append(fix)
count += 1
if len(to_update) >= batch_size:
PublicLightingLightFixture.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'street'])
to_update = []
if to_update:
PublicLightingLightFixture.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'street'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Public Lighting Light Fixtures"))
# 10. ITS Assets
self.stdout.write("10. Syncing ITS Assets...")
its_assets = ITSGeoAsset.objects.select_related('trafficlights_pole', 'lighting_pole')
count = 0
to_update = []
for its in its_assets.iterator(chunk_size=batch_size):
support = its.trafficlights_pole or its.lighting_pole
if support and getattr(support, 'geom', None):
if its.geom != support.geom or its.lon != support.lon or its.lat != support.lat:
its.geom = support.geom
its.lon = support.lon
its.lat = support.lat
its.geojson = support.geojson
to_update.append(its)
count += 1
if len(to_update) >= batch_size:
ITSGeoAsset.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson'])
to_update = []
if to_update:
ITSGeoAsset.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} ITS Assets"))
# 11. Structure Assets
self.stdout.write("11. Syncing Structure Assets...")
struct_assets = StructureGeoAsset.objects.select_related('parent_asset')
count = 0
to_update = []
for sa in struct_assets.iterator(chunk_size=batch_size):
changed = False
if sa.parent_asset and getattr(sa.parent_asset, 'geom', None) and not sa.geom:
sa.geom = sa.parent_asset.geom
sa.lon = sa.parent_asset.lon
sa.lat = sa.parent_asset.lat
sa.geojson = sa.parent_asset.geojson
changed = True
if sa.parent_asset and sa.parent_asset.location and not sa.location_id:
sa.location = sa.parent_asset.location
changed = True
if sa.parent_asset and sa.parent_asset.structure and not sa.structure_id:
sa.structure = sa.parent_asset.structure
changed = True
if changed:
to_update.append(sa)
count += 1
if len(to_update) >= batch_size:
StructureGeoAsset.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'location', 'structure'])
to_update = []
if to_update:
StructureGeoAsset.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'location', 'structure'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Structure Assets"))
# 12. Building Assets
self.stdout.write("12. Syncing Building Assets...")
bld_assets = BuildingAsset.objects.select_related('parent_asset')
count = 0
to_update = []
for ba in bld_assets.iterator(chunk_size=batch_size):
changed = False
if ba.parent_asset and getattr(ba.parent_asset, 'geom', None) and not ba.geom:
ba.geom = ba.parent_asset.geom
ba.lon = ba.parent_asset.lon
ba.lat = ba.parent_asset.lat
ba.geojson = ba.parent_asset.geojson
changed = True
if ba.parent_asset and ba.parent_asset.location and not ba.location_id:
ba.location = ba.parent_asset.location
changed = True
if ba.parent_asset and ba.parent_asset.building and not ba.building_id:
ba.building = ba.parent_asset.building
changed = True
if changed:
to_update.append(ba)
count += 1
if len(to_update) >= batch_size:
BuildingAsset.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'location', 'building'])
to_update = []
if to_update:
BuildingAsset.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'location', 'building'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Building Assets"))
# 13. Outdoor Assets
self.stdout.write("13. Syncing Outdoor Assets...")
out_assets = OutdoorAsset.objects.select_related('parent_asset')
count = 0
to_update = []
for oa in out_assets.iterator(chunk_size=batch_size):
changed = False
if oa.parent_asset and getattr(oa.parent_asset, 'geom', None) and not oa.geom:
oa.geom = oa.parent_asset.geom
oa.lon = oa.parent_asset.lon
oa.lat = oa.parent_asset.lat
oa.geojson = oa.parent_asset.geojson
changed = True
if oa.parent_asset and oa.parent_asset.location and not oa.location_id:
oa.location = oa.parent_asset.location
changed = True
if oa.parent_asset and oa.parent_asset.site and not oa.site_id:
oa.site = oa.parent_asset.site
changed = True
if changed:
to_update.append(oa)
count += 1
if len(to_update) >= batch_size:
OutdoorAsset.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'location', 'site'])
to_update = []
if to_update:
OutdoorAsset.objects.bulk_update(to_update, ['geom', 'lon', 'lat', 'geojson', 'location', 'site'])
self.stdout.write(self.style.SUCCESS(f" ✓ Updated {count} Outdoor Assets"))
self.stdout.write(self.style.SUCCESS("All asset parent data synchronized successfully!"))