Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions netbox_custom_objects/field_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -754,7 +754,8 @@ def get_model_field(self, field, **kwargs):

# Extract our custom parameters and keep only Django field parameters
field_kwargs = {k: v for k, v in kwargs.items() if not k.startswith('_')}
field_kwargs.update({"default": field.default, "unique": field.unique})
# Remove default from field_kwargs since ManyToManyField doesn't handle defaults the same way
field_kwargs.update({"unique": field.unique})

is_self_referential = (
content_type.app_label == APP_LABEL
Expand Down Expand Up @@ -825,15 +826,13 @@ def get_form_field(self, field, for_csv_import=False, **kwargs):
return field_class(
queryset=model.objects.all(),
required=field.required,
# Remove initial=field.default to allow Django to handle instance data properly
to_field_name=to_field_name,
)
else:
field_class = DynamicModelMultipleChoiceField
return field_class(
queryset=model.objects.all(),
required=field.required,
# Remove initial=field.default to allow Django to handle instance data properly
query_params=(
field.related_object_filter
if hasattr(field, "related_object_filter")
Expand Down
39 changes: 38 additions & 1 deletion netbox_custom_objects/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from . import field_types, filtersets, forms, tables
from .models import CustomObject, CustomObjectType, CustomObjectTypeField
from extras.choices import CustomFieldTypeChoices
from netbox_custom_objects.constants import APP_LABEL

logger = logging.getLogger("netbox_custom_objects.views")

Expand Down Expand Up @@ -493,13 +494,49 @@ def get_form(self, model):

# Create a custom __init__ method to set instance attributes
def custom_init(self, *args, **kwargs):
forms.NetBoxModelForm.__init__(self, *args, **kwargs)
# Set the grouping info as instance attributes from the outer scope
self.custom_object_type_fields = attrs["custom_object_type_fields"]
self.custom_object_type_field_groups = attrs[
"custom_object_type_field_groups"
]

# Handle default values for MultiObject fields BEFORE calling parent __init__
# This ensures the initial values are set before Django processes the form
instance = kwargs.get('instance', None)
if not instance or not instance.pk:
# Only set defaults for new instances (not when editing existing ones)
for field_name, field_obj in self.custom_object_type_fields.items():
if field_obj.type == CustomFieldTypeChoices.TYPE_MULTIOBJECT:
if field_obj.default and isinstance(field_obj.default, list):
# Get the related model
content_type = field_obj.related_object_type
if content_type.app_label == APP_LABEL:
# Custom object type
from netbox_custom_objects.models import CustomObjectType
custom_object_type_id = content_type.model.replace("table", "").replace("model", "")
custom_object_type = CustomObjectType.objects.get(pk=custom_object_type_id)
model = custom_object_type.get_model(skip_object_fields=True)
else:
# Regular NetBox model
model = content_type.model_class()

try:
# Query the database to get the actual objects
initial_objects = model.objects.filter(pk__in=field_obj.default)
# Convert to list of IDs for ModelMultipleChoiceField
initial_ids = list(initial_objects.values_list('pk', flat=True))

# Set the initial value in the form's initial data
if 'initial' not in kwargs:
kwargs['initial'] = {}
kwargs['initial'][field_name] = initial_ids
except Exception:
# If there's an error, don't set initial values
pass

# Now call the parent __init__ with the modified kwargs
forms.NetBoxModelForm.__init__(self, *args, **kwargs)

# Create a custom save method to properly handle M2M fields
def custom_save(self, commit=True):
# First save the instance to get the primary key
Expand Down