Skip to content

Commit 1a25f5a

Browse files
committed
Fixes #4030: Fix exception when bulk editing interfaces (revised)
1 parent b9765b8 commit 1a25f5a

File tree

3 files changed

+22
-9
lines changed

3 files changed

+22
-9
lines changed

docs/release-notes/version-2.7.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
## Bug Fixes
88

9+
* [#4030](https://github.com/netbox-community/netbox/issues/4030) - Fix exception when bulk editing interfaces (revised)
910
* [#4043](https://github.com/netbox-community/netbox/issues/4043) - Fix toggling of required fields in custom scripts
1011
* [#4049](https://github.com/netbox-community/netbox/issues/4049) - Restore missing `tags` field in IPAM service serializer
1112
* [#4052](https://github.com/netbox-community/netbox/issues/4052) - Fix error when bulk importing interfaces to virtual machines

netbox/dcim/models/device_components.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -676,7 +676,7 @@ def save(self, *args, **kwargs):
676676
self.untagged_vlan = None
677677

678678
# Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.)
679-
if self.pk and self.mode is not InterfaceModeChoices.MODE_TAGGED:
679+
if self.pk and self.mode != InterfaceModeChoices.MODE_TAGGED:
680680
self.tagged_vlans.clear()
681681

682682
return super().save(*args, **kwargs)

netbox/utilities/views.py

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from django.contrib.contenttypes.models import ContentType
77
from django.core.exceptions import ValidationError
88
from django.db import transaction, IntegrityError
9-
from django.db.models import Count, ProtectedError
9+
from django.db.models import Count, ManyToManyField, ProtectedError
1010
from django.db.models.query import QuerySet
1111
from django.forms import CharField, Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
1212
from django.http import HttpResponse, HttpResponseServerError
@@ -650,7 +650,9 @@ def post(self, request, **kwargs):
650650
if form.is_valid():
651651

652652
custom_fields = form.custom_fields if hasattr(form, 'custom_fields') else []
653-
standard_fields = [field for field in form.fields if field not in custom_fields and field != 'pk']
653+
standard_fields = [
654+
field for field in form.fields if field not in custom_fields + ['pk', 'add_tags', 'remove_tags']
655+
]
654656
nullified_fields = request.POST.getlist('_nullify')
655657

656658
try:
@@ -662,14 +664,24 @@ def post(self, request, **kwargs):
662664

663665
# Update standard fields. If a field is listed in _nullify, delete its value.
664666
for name in standard_fields:
665-
if name in form.nullable_fields and name in nullified_fields and isinstance(form.cleaned_data[name], QuerySet):
666-
getattr(obj, name).set([])
667-
elif name in form.nullable_fields and name in nullified_fields:
668-
setattr(obj, name, '' if isinstance(form.fields[name], CharField) else None)
669-
elif isinstance(form.cleaned_data[name], QuerySet) and form.cleaned_data[name]:
667+
668+
model_field = model._meta.get_field(name)
669+
670+
# Handle nullification
671+
if name in form.nullable_fields and name in nullified_fields:
672+
if isinstance(model_field, ManyToManyField):
673+
getattr(obj, name).set([])
674+
else:
675+
setattr(obj, name, None if model_field.null else '')
676+
677+
# ManyToManyFields
678+
elif isinstance(model_field, ManyToManyField):
670679
getattr(obj, name).set(form.cleaned_data[name])
671-
elif form.cleaned_data[name] not in (None, '') and not isinstance(form.cleaned_data[name], QuerySet):
680+
681+
# Normal fields
682+
elif form.cleaned_data[name] not in (None, ''):
672683
setattr(obj, name, form.cleaned_data[name])
684+
673685
obj.full_clean()
674686
obj.save()
675687

0 commit comments

Comments
 (0)