fix: resolve constrained relations before insert
This commit is contained in:
@@ -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.4"
|
||||
version = "0.3.5"
|
||||
author = "NetBox Export contributors"
|
||||
base_url = "netbox-export"
|
||||
min_version = "4.6.0"
|
||||
|
||||
@@ -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.4",
|
||||
"plugin_version": "0.3.5",
|
||||
"scope": {
|
||||
"type": scope_type,
|
||||
"source_pk": str(scope_id),
|
||||
|
||||
@@ -19,6 +19,7 @@ from .exceptions import ArchiveValidationError, ExportImportError, ImportConflic
|
||||
from .plugin_compat import (
|
||||
PluginCompatibility,
|
||||
is_tenant_relation,
|
||||
relation_required_before_save,
|
||||
)
|
||||
from .references import MISSING_REFERENCE, ReferenceResolver
|
||||
|
||||
@@ -245,16 +246,19 @@ def _field_kwargs(model, record, resolver, *, tenant_required: bool):
|
||||
if not isinstance(field, (models.ForeignKey, models.OneToOneField)):
|
||||
continue
|
||||
tenant_relation = is_tenant_relation(field)
|
||||
required_before_save = relation_required_before_save(field)
|
||||
value, available = resolver.resolve(spec)
|
||||
if available:
|
||||
if value is MISSING_REFERENCE:
|
||||
if not field.null and not field.has_default():
|
||||
if (required_before_save and not tenant_relation) or (
|
||||
not field.null and not field.has_default() and not tenant_relation
|
||||
):
|
||||
missing_required.append(name)
|
||||
elif value is None and tenant_relation and tenant_required:
|
||||
continue
|
||||
else:
|
||||
kwargs[name] = value
|
||||
elif field.null and not tenant_relation:
|
||||
elif field.null and not required_before_save:
|
||||
unresolved.append((name, spec))
|
||||
else:
|
||||
return None, [], [], []
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import cache
|
||||
|
||||
from django.apps import apps
|
||||
from django.core.exceptions import FieldDoesNotExist, ValidationError
|
||||
from django.db import models
|
||||
|
||||
AUTO_IMPORT_TENANT_NAME = "Auto-Import"
|
||||
AUTO_IMPORT_TENANT_SLUG = "auto-import"
|
||||
@@ -24,6 +27,31 @@ def is_tenant_relation(field) -> bool:
|
||||
return getattr(getattr(related_model, "_meta", None), "label_lower", None) == "tenancy.tenant"
|
||||
|
||||
|
||||
def _condition_field_names(condition):
|
||||
for child in getattr(condition, "children", ()):
|
||||
if isinstance(child, tuple):
|
||||
yield child[0].split("__", 1)[0]
|
||||
else:
|
||||
yield from _condition_field_names(child)
|
||||
|
||||
|
||||
@cache
|
||||
def check_constraint_field_names(model) -> frozenset[str]:
|
||||
if model is None:
|
||||
return frozenset()
|
||||
names = set()
|
||||
for constraint in model._meta.constraints:
|
||||
if isinstance(constraint, models.CheckConstraint):
|
||||
names.update(_condition_field_names(constraint.condition))
|
||||
return frozenset(names)
|
||||
|
||||
|
||||
def relation_required_before_save(field) -> bool:
|
||||
return is_tenant_relation(field) or field.name in check_constraint_field_names(
|
||||
getattr(field, "model", None)
|
||||
)
|
||||
|
||||
|
||||
class PluginCompatibility:
|
||||
def __init__(
|
||||
self,
|
||||
|
||||
Reference in New Issue
Block a user