fix: reassign unique imported relations atomically

This commit is contained in:
2026-08-05 13:56:16 +02:00
parent 3eb1729c93
commit f22276d68d
8 changed files with 134 additions and 4 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ class NetBoxExportConfig(PluginConfig):
name = "netbox_export"
verbose_name = "NetBox-Export"
description = "Portable ZIP export and import for tenants and locations"
version = "0.3.5"
version = "0.3.6"
author = "NetBox Export contributors"
base_url = "netbox-export"
min_version = "4.6.0"
+1 -1
View File
@@ -39,7 +39,7 @@ def export_scope(
"created_at": datetime.now(UTC).isoformat(),
"source_instance": str(InstanceIdentity.local_id()),
"source_netbox_version": getattr(getattr(settings, "RELEASE", None), "version", "4.6"),
"plugin_version": "0.3.5",
"plugin_version": "0.3.6",
"scope": {
"type": scope_type,
"source_pk": str(scope_id),
+4
View File
@@ -20,6 +20,7 @@ from .plugin_compat import (
PluginCompatibility,
is_tenant_relation,
relation_required_before_save,
relation_should_be_deferred,
)
from .references import MISSING_REFERENCE, ReferenceResolver
@@ -256,6 +257,8 @@ def _field_kwargs(model, record, resolver, *, tenant_required: bool):
missing_required.append(name)
elif value is None and tenant_relation and tenant_required:
continue
elif value is not None and relation_should_be_deferred(field):
unresolved.append((name, spec))
else:
kwargs[name] = value
elif field.null and not required_before_save:
@@ -431,6 +434,7 @@ def import_archive(parsed: ParsedArchive, *, conflict_strategy: str, dry_run: bo
if value is MISSING_REFERENCE:
continue
obj = resolved[record_id]
compatibility.release_unique_relation(obj, name, value)
setattr(obj, name, value)
compatibility.save(obj, update_fields=[name])
+23
View File
@@ -52,6 +52,10 @@ def relation_required_before_save(field) -> bool:
)
def relation_should_be_deferred(field) -> bool:
return bool(field.null and field.unique and not relation_required_before_save(field))
class PluginCompatibility:
def __init__(
self,
@@ -131,3 +135,22 @@ class PluginCompatibility:
if not self._is_missing_tenant_error(exc) or not self._assign_fallback_tenant(obj, force=True):
raise
return obj.save(**kwargs)
def release_unique_relation(self, obj, field_name: str, value):
field = obj._meta.get_field(field_name)
if value is None or not relation_should_be_deferred(field):
return
conflicts = type(obj)._default_manager.filter(**{field.attname: value.pk})
if obj.pk is not None:
conflicts = conflicts.exclude(pk=obj.pk)
conflict_ids = list(conflicts.values_list("pk", flat=True))
if not conflict_ids:
return
type(obj)._default_manager.filter(pk__in=conflict_ids).update(**{field.attname: None})
identifiers = ", ".join(str(pk) for pk in conflict_ids)
self.warnings.append(
f"Eindeutige Referenz {obj._meta.label_lower}.{field_name} wurde von Zielobjekt(en) "
f"{identifiers} gelöst und dem importierten Objekt neu zugeordnet."
)