379 lines
19 KiB
Python
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!"))
|