Preserve sub-component hierarchy in export/import
This commit is contained in:
@@ -1193,11 +1193,13 @@ def create_app(config_object="config"):
|
||||
buf = io.StringIO()
|
||||
w = csv.writer(buf)
|
||||
w.writerow(["id", "name", "battery_slots", "installed_count",
|
||||
"device_type", "battery_size", "location", "ha_entity_id", "notes"])
|
||||
"device_type", "battery_size", "location", "ha_entity_id", "notes",
|
||||
"parent_id", "parent_name"])
|
||||
for d in rows:
|
||||
w.writerow([d.id, d.name, d.battery_slots, d.installed_count(),
|
||||
d.device_type or "", d.battery_size or "",
|
||||
d.location or "", d.ha_entity_id or "", d.notes or ""])
|
||||
d.location or "", d.ha_entity_id or "", d.notes or "",
|
||||
d.parent_id or "", d.parent.name if d.parent else ""])
|
||||
return buf.getvalue()
|
||||
|
||||
def _charge_logs_csv():
|
||||
@@ -1296,7 +1298,9 @@ def create_app(config_object="config"):
|
||||
{"id": d.id, "name": d.name, "battery_slots": d.battery_slots,
|
||||
"installed_count": d.installed_count(), "device_type": d.device_type,
|
||||
"battery_size": d.battery_size, "location": d.location,
|
||||
"ha_entity_id": d.ha_entity_id, "notes": d.notes}
|
||||
"ha_entity_id": d.ha_entity_id, "notes": d.notes,
|
||||
"parent_id": d.parent_id,
|
||||
"parent_name": d.parent.name if d.parent else None}
|
||||
for d in devices
|
||||
],
|
||||
"charge_logs": [
|
||||
@@ -1366,29 +1370,33 @@ def create_app(config_object="config"):
|
||||
|
||||
try:
|
||||
# --- devices ---
|
||||
for d in data.get("devices", []):
|
||||
def _import_device(d, new_parent_id):
|
||||
nonlocal devices_created, devices_skipped
|
||||
old_id = d.get("id")
|
||||
name = (d.get("name") or "").strip()
|
||||
if not name:
|
||||
devices_skipped += 1
|
||||
continue
|
||||
return
|
||||
parent_key = new_parent_id if new_parent_id is not None else -1
|
||||
existing = db.query(Device).filter(
|
||||
Device.parent_key == -1, Device.name == name
|
||||
Device.parent_key == parent_key, Device.name == name
|
||||
).first()
|
||||
if existing:
|
||||
if old_id is not None:
|
||||
device_id_map[old_id] = existing.id
|
||||
devices_skipped += 1
|
||||
else:
|
||||
slots = d.get("battery_slots")
|
||||
new_dev = Device(
|
||||
name = name,
|
||||
battery_slots = d.get("battery_slots") or 1,
|
||||
battery_slots = slots if slots is not None else 1,
|
||||
device_type = d.get("device_type") or None,
|
||||
battery_size = d.get("battery_size") or "",
|
||||
battery_size = d.get("battery_size") or None,
|
||||
location = d.get("location") or None,
|
||||
ha_entity_id = d.get("ha_entity_id") or None,
|
||||
notes = d.get("notes") or None,
|
||||
parent_key = -1,
|
||||
parent_id = new_parent_id,
|
||||
parent_key = parent_key,
|
||||
)
|
||||
db.add(new_dev)
|
||||
db.flush()
|
||||
@@ -1396,6 +1404,17 @@ def create_app(config_object="config"):
|
||||
device_id_map[old_id] = new_dev.id
|
||||
devices_created += 1
|
||||
|
||||
# Two passes so sub-components can resolve their parent's new id
|
||||
# regardless of ordering in the payload. A sub whose parent is
|
||||
# missing from the payload is imported as top-level.
|
||||
device_rows = data.get("devices", [])
|
||||
for d in device_rows:
|
||||
if d.get("parent_id") is None:
|
||||
_import_device(d, None)
|
||||
for d in device_rows:
|
||||
if d.get("parent_id") is not None:
|
||||
_import_device(d, device_id_map.get(d.get("parent_id")))
|
||||
|
||||
# --- batteries ---
|
||||
for b in data.get("batteries", []):
|
||||
old_id = b.get("id")
|
||||
|
||||
Reference in New Issue
Block a user