Skip to content

Commit

Permalink
Fixes #13843: Fix assignment of VLAN group scope during bulk edit (#1…
Browse files Browse the repository at this point in the history
…3887)

* Update VLANGroup bulk edit form to support all scope types

* Fixes #13843: Fix scope assignment for VLAN groups during bulk edit

* Add missed static file

* Restore graphiql static assets
  • Loading branch information
jeremystretch authored Sep 26, 2023
1 parent b759d69 commit 1ad6d94
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 11 deletions.
85 changes: 77 additions & 8 deletions netbox/ipam/forms/bulk_edit.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext_lazy as _

from dcim.models import Region, Site, SiteGroup
from dcim.models import Location, Rack, Region, Site, SiteGroup
from ipam.choices import *
from ipam.constants import *
from ipam.models import *
Expand All @@ -10,9 +11,10 @@
from tenancy.models import Tenant
from utilities.forms import add_blank_choice
from utilities.forms.fields import (
CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
)
from utilities.forms.widgets import BulkEditNullBooleanSelect
from virtualization.models import Cluster, ClusterGroup

__all__ = (
'AggregateBulkEditForm',
Expand Down Expand Up @@ -407,11 +409,6 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm):


class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
site = DynamicModelChoiceField(
label=_('Site'),
queryset=Site.objects.all(),
required=False
)
min_vid = forms.IntegerField(
min_value=VLAN_VID_MIN,
max_value=VLAN_VID_MAX,
Expand All @@ -429,12 +426,84 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
max_length=200,
required=False
)
scope_type = ContentTypeChoiceField(
label=_('Scope type'),
queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
required=False
)
scope_id = forms.IntegerField(
required=False,
widget=forms.HiddenInput()
)
region = DynamicModelChoiceField(
label=_('Region'),
queryset=Region.objects.all(),
required=False
)
sitegroup = DynamicModelChoiceField(
queryset=SiteGroup.objects.all(),
required=False,
label=_('Site group')
)
site = DynamicModelChoiceField(
label=_('Site'),
queryset=Site.objects.all(),
required=False,
query_params={
'region_id': '$region',
'group_id': '$sitegroup',
}
)
location = DynamicModelChoiceField(
label=_('Location'),
queryset=Location.objects.all(),
required=False,
query_params={
'site_id': '$site',
}
)
rack = DynamicModelChoiceField(
label=_('Rack'),
queryset=Rack.objects.all(),
required=False,
query_params={
'site_id': '$site',
'location_id': '$location',
}
)
clustergroup = DynamicModelChoiceField(
queryset=ClusterGroup.objects.all(),
required=False,
label=_('Cluster group')
)
cluster = DynamicModelChoiceField(
label=_('Cluster'),
queryset=Cluster.objects.all(),
required=False,
query_params={
'group_id': '$clustergroup',
}
)

model = VLANGroup
fieldsets = (
(None, ('site', 'min_vid', 'max_vid', 'description')),
(_('Scope'), ('scope_type', 'region', 'sitegroup', 'site', 'location', 'rack', 'clustergroup', 'cluster')),
)
nullable_fields = ('site', 'description')
nullable_fields = ('description',)

def clean(self):
super().clean()

# Assign scope based on scope_type
if self.cleaned_data.get('scope_type'):
scope_field = self.cleaned_data['scope_type'].model
if scope_obj := self.cleaned_data.get(scope_field):
self.cleaned_data['scope_id'] = scope_obj.pk
self.changed_data.append('scope_id')
else:
self.cleaned_data.pop('scope_type')
self.changed_data.remove('scope_type')


class VLANBulkEditForm(NetBoxModelBulkEditForm):
Expand Down
5 changes: 4 additions & 1 deletion netbox/netbox/views/generic/bulk_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from copy import deepcopy

from django.contrib import messages
from django.contrib.contenttypes.fields import GenericRel
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError
from django.db import transaction, IntegrityError
Expand Down Expand Up @@ -519,9 +520,11 @@ def _update_objects(self, form, request):
model_field = self.queryset.model._meta.get_field(name)
if isinstance(model_field, (ManyToManyField, ManyToManyRel)):
m2m_fields[name] = model_field
elif isinstance(model_field, GenericRel):
# Ignore generic relations (these may be used for other purposes in the form)
continue
else:
model_fields[name] = model_field

except FieldDoesNotExist:
# This form field is used to modify a field rather than set its value directly
model_fields[name] = None
Expand Down
2 changes: 1 addition & 1 deletion netbox/project-static/dist/netbox.js

Large diffs are not rendered by default.

Loading

0 comments on commit 1ad6d94

Please sign in to comment.