Coverage for ipam/forms/bulk_edit.py: 100%
140 statements
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
« prev ^ index » next coverage.py v7.15.2, created at 2026-10-10 18:35 +0000
1from django import forms
2from django.contrib.contenttypes.models import ContentType
3from django.utils.translation import gettext_lazy as _
5from dcim.forms.mixins import ScopedBulkEditForm
6from dcim.models import Region, Site, SiteGroup
7from ipam.choices import *
8from ipam.constants import *
9from ipam.forms.fields import PortMappingField
10from ipam.models import *
11from ipam.models import ASN
12from netbox.forms import NetBoxModelBulkEditForm, OrganizationalModelBulkEditForm, PrimaryModelBulkEditForm
13from tenancy.models import Tenant
14from utilities.forms import GenericObjectFormMixin, add_blank_choice
15from utilities.forms.fields import (
16 ChoiceField,
17 DynamicModelChoiceField,
18 DynamicModelMultipleChoiceField,
19 GenericObjectChoiceField,
20 NumericRangeArrayField,
21)
22from utilities.forms.rendering import FieldSet
23from utilities.forms.widgets import BulkEditNullBooleanSelect
25__all__ = (
26 'ASNBulkEditForm',
27 'ASNRangeBulkEditForm',
28 'AggregateBulkEditForm',
29 'FHRPGroupBulkEditForm',
30 'IPAddressBulkEditForm',
31 'IPRangeBulkEditForm',
32 'PrefixBulkEditForm',
33 'RIRBulkEditForm',
34 'RoleBulkEditForm',
35 'RouteTargetBulkEditForm',
36 'ServiceBulkEditForm',
37 'ServiceTemplateBulkEditForm',
38 'VLANBulkEditForm',
39 'VLANGroupBulkEditForm',
40 'VLANTranslationPolicyBulkEditForm',
41 'VLANTranslationRuleBulkEditForm',
42 'VRFBulkEditForm',
43)
46class VRFBulkEditForm(PrimaryModelBulkEditForm):
47 tenant = DynamicModelChoiceField(
48 label=_('Tenant'),
49 queryset=Tenant.objects.all(),
50 required=False
51 )
52 enforce_unique = forms.NullBooleanField(
53 required=False,
54 widget=BulkEditNullBooleanSelect(),
55 label=_('Enforce unique space')
56 )
58 model = VRF
59 fieldsets = (
60 FieldSet('tenant', 'enforce_unique', 'description'),
61 )
62 nullable_fields = ('tenant', 'description', 'comments')
65class RouteTargetBulkEditForm(PrimaryModelBulkEditForm):
66 tenant = DynamicModelChoiceField(
67 label=_('Tenant'),
68 queryset=Tenant.objects.all(),
69 required=False
70 )
72 model = RouteTarget
73 fieldsets = (
74 FieldSet('tenant', 'description'),
75 )
76 nullable_fields = ('tenant', 'description', 'comments')
79class RIRBulkEditForm(OrganizationalModelBulkEditForm):
80 is_private = forms.NullBooleanField(
81 label=_('Is private'),
82 required=False,
83 widget=BulkEditNullBooleanSelect
84 )
86 model = RIR
87 fieldsets = (
88 FieldSet('is_private', 'description'),
89 )
90 nullable_fields = ('is_private', 'description', 'comments')
93class ASNRangeBulkEditForm(OrganizationalModelBulkEditForm):
94 rir = DynamicModelChoiceField(
95 queryset=RIR.objects.all(),
96 required=False,
97 label=_('RIR')
98 )
99 tenant = DynamicModelChoiceField(
100 label=_('Tenant'),
101 queryset=Tenant.objects.all(),
102 required=False
103 )
105 model = ASNRange
106 fieldsets = (
107 FieldSet('rir', 'tenant', 'description'),
108 )
109 nullable_fields = ('description', 'comments')
112class ASNBulkEditForm(PrimaryModelBulkEditForm):
113 sites = DynamicModelMultipleChoiceField(
114 label=_('Sites'),
115 queryset=Site.objects.all(),
116 required=False
117 )
118 rir = DynamicModelChoiceField(
119 queryset=RIR.objects.all(),
120 required=False,
121 label=_('RIR')
122 )
123 role = DynamicModelChoiceField(
124 queryset=Role.objects.all(),
125 required=False,
126 label=_('Role')
127 )
128 tenant = DynamicModelChoiceField(
129 label=_('Tenant'),
130 queryset=Tenant.objects.all(),
131 required=False
132 )
134 model = ASN
135 fieldsets = (
136 FieldSet('sites', 'rir', 'role', 'tenant', 'description'),
137 )
138 nullable_fields = ('role', 'tenant', 'description', 'comments')
141class AggregateBulkEditForm(PrimaryModelBulkEditForm):
142 rir = DynamicModelChoiceField(
143 queryset=RIR.objects.all(),
144 required=False,
145 label=_('RIR')
146 )
147 tenant = DynamicModelChoiceField(
148 label=_('Tenant'),
149 queryset=Tenant.objects.all(),
150 required=False
151 )
152 date_added = forms.DateField(
153 label=_('Date added'),
154 required=False
155 )
157 model = Aggregate
158 fieldsets = (
159 FieldSet('rir', 'tenant', 'date_added', 'description'),
160 )
161 nullable_fields = ('date_added', 'description', 'comments')
164class RoleBulkEditForm(OrganizationalModelBulkEditForm):
165 weight = forms.IntegerField(
166 label=_('Weight'),
167 required=False
168 )
170 model = Role
171 fieldsets = (
172 FieldSet('weight', 'description'),
173 )
174 nullable_fields = ('description', 'comments')
177class PrefixBulkEditForm(ScopedBulkEditForm, PrimaryModelBulkEditForm):
178 vlan_group = DynamicModelChoiceField(
179 queryset=VLANGroup.objects.all(),
180 required=False,
181 label=_('VLAN Group')
182 )
183 vlan = DynamicModelChoiceField(
184 queryset=VLAN.objects.all(),
185 required=False,
186 label=_('VLAN'),
187 query_params={
188 'group_id': '$vlan_group',
189 }
190 )
191 vrf = DynamicModelChoiceField(
192 queryset=VRF.objects.all(),
193 required=False,
194 label=_('VRF')
195 )
196 prefix_length = forms.IntegerField(
197 label=_('Prefix length'),
198 min_value=PREFIX_LENGTH_MIN,
199 max_value=PREFIX_LENGTH_MAX,
200 required=False
201 )
202 tenant = DynamicModelChoiceField(
203 label=_('Tenant'),
204 queryset=Tenant.objects.all(),
205 required=False
206 )
207 status = ChoiceField(
208 label=_('Status'),
209 choices=add_blank_choice(PrefixStatusChoices),
210 required=False
211 )
212 role = DynamicModelChoiceField(
213 label=_('Role'),
214 queryset=Role.objects.all(),
215 required=False
216 )
217 is_pool = forms.NullBooleanField(
218 required=False,
219 widget=BulkEditNullBooleanSelect(),
220 label=_('Is a pool')
221 )
222 mark_utilized = forms.NullBooleanField(
223 required=False,
224 widget=BulkEditNullBooleanSelect(),
225 label=_('Treat as fully utilized')
226 )
228 model = Prefix
229 fieldsets = (
230 FieldSet('tenant', 'status', 'role', 'description'),
231 FieldSet('vrf', 'prefix_length', 'is_pool', 'mark_utilized', name=_('Addressing')),
232 FieldSet('scope', name=_('Scope')),
233 FieldSet('vlan_group', 'vlan', name=_('VLAN Assignment')),
234 )
235 nullable_fields = (
236 'vlan', 'vrf', 'tenant', 'role', 'scope', 'description', 'comments',
237 )
240class IPRangeBulkEditForm(PrimaryModelBulkEditForm):
241 vrf = DynamicModelChoiceField(
242 queryset=VRF.objects.all(),
243 required=False,
244 label=_('VRF')
245 )
246 tenant = DynamicModelChoiceField(
247 label=_('Tenant'),
248 queryset=Tenant.objects.all(),
249 required=False
250 )
251 status = ChoiceField(
252 label=_('Status'),
253 choices=add_blank_choice(IPRangeStatusChoices),
254 required=False
255 )
256 role = DynamicModelChoiceField(
257 label=_('Role'),
258 queryset=Role.objects.all(),
259 required=False
260 )
261 mark_populated = forms.NullBooleanField(
262 required=False,
263 widget=BulkEditNullBooleanSelect(),
264 label=_('Treat as populated')
265 )
266 mark_utilized = forms.NullBooleanField(
267 required=False,
268 widget=BulkEditNullBooleanSelect(),
269 label=_('Treat as fully utilized')
270 )
272 model = IPRange
273 fieldsets = (
274 FieldSet('status', 'role', 'vrf', 'tenant', 'mark_utilized', 'description'),
275 )
276 nullable_fields = (
277 'vrf', 'tenant', 'role', 'description', 'comments',
278 )
281class IPAddressBulkEditForm(PrimaryModelBulkEditForm):
282 vrf = DynamicModelChoiceField(
283 queryset=VRF.objects.all(),
284 required=False,
285 label=_('VRF')
286 )
287 mask_length = forms.IntegerField(
288 label=_('Mask length'),
289 min_value=IPADDRESS_MASK_LENGTH_MIN,
290 max_value=IPADDRESS_MASK_LENGTH_MAX,
291 required=False
292 )
293 tenant = DynamicModelChoiceField(
294 label=_('Tenant'),
295 queryset=Tenant.objects.all(),
296 required=False
297 )
298 status = ChoiceField(
299 label=_('Status'),
300 choices=add_blank_choice(IPAddressStatusChoices),
301 required=False
302 )
303 role = ChoiceField(
304 label=_('Role'),
305 choices=add_blank_choice(IPAddressRoleChoices),
306 required=False
307 )
308 dns_name = forms.CharField(
309 max_length=255,
310 required=False,
311 label=_('DNS name')
312 )
314 model = IPAddress
315 fieldsets = (
316 FieldSet('status', 'role', 'tenant', 'description'),
317 FieldSet('vrf', 'mask_length', 'dns_name', name=_('Addressing')),
318 )
319 nullable_fields = (
320 'vrf', 'role', 'tenant', 'dns_name', 'description', 'comments',
321 )
324class FHRPGroupBulkEditForm(PrimaryModelBulkEditForm):
325 protocol = ChoiceField(
326 label=_('Protocol'),
327 choices=add_blank_choice(FHRPGroupProtocolChoices),
328 required=False
329 )
330 group_id = forms.IntegerField(
331 min_value=0,
332 required=False,
333 label=_('Group ID')
334 )
335 auth_type = ChoiceField(
336 choices=add_blank_choice(FHRPGroupAuthTypeChoices),
337 required=False,
338 label=_('Authentication type')
339 )
340 auth_key = forms.CharField(
341 max_length=255,
342 required=False,
343 label=_('Authentication key')
344 )
345 name = forms.CharField(
346 label=_('Name'),
347 max_length=100,
348 required=False
349 )
351 model = FHRPGroup
352 fieldsets = (
353 FieldSet('protocol', 'group_id', 'name', 'description'),
354 FieldSet('auth_type', 'auth_key', name=_('Authentication')),
355 )
356 nullable_fields = ('auth_type', 'auth_key', 'name', 'description', 'comments')
359class VLANGroupBulkEditForm(GenericObjectFormMixin, OrganizationalModelBulkEditForm):
360 scope = GenericObjectChoiceField(
361 label=_('Scope'),
362 content_type_queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
363 required=False,
364 selector=True,
365 hx_method='post',
366 )
367 vid_ranges = NumericRangeArrayField(
368 label=_('VLAN ID ranges'),
369 required=False
370 )
371 tenant = DynamicModelChoiceField(
372 label=_('Tenant'),
373 queryset=Tenant.objects.all(),
374 required=False
375 )
377 model = VLANGroup
378 fieldsets = (
379 FieldSet('site', 'vid_ranges', 'description'),
380 FieldSet('scope', name=_('Scope')),
381 FieldSet('tenant', name=_('Tenancy')),
382 )
383 nullable_fields = ('description', 'scope', 'comments')
386class VLANBulkEditForm(PrimaryModelBulkEditForm):
387 region = DynamicModelChoiceField(
388 label=_('Region'),
389 queryset=Region.objects.all(),
390 required=False
391 )
392 site_group = DynamicModelChoiceField(
393 label=_('Site group'),
394 queryset=SiteGroup.objects.all(),
395 required=False
396 )
397 site = DynamicModelChoiceField(
398 label=_('Site'),
399 queryset=Site.objects.all(),
400 required=False,
401 query_params={
402 'region_id': '$region',
403 'group_id': '$site_group',
404 }
405 )
406 group = DynamicModelChoiceField(
407 label=_('Group'),
408 queryset=VLANGroup.objects.all(),
409 required=False,
410 query_params={
411 'site_id': '$site'
412 }
413 )
414 tenant = DynamicModelChoiceField(
415 label=_('Tenant'),
416 queryset=Tenant.objects.all(),
417 required=False
418 )
419 status = ChoiceField(
420 label=_('Status'),
421 choices=add_blank_choice(VLANStatusChoices),
422 required=False
423 )
424 role = DynamicModelChoiceField(
425 label=_('Role'),
426 queryset=Role.objects.all(),
427 required=False
428 )
429 qinq_role = ChoiceField(
430 label=_('Q-in-Q role'),
431 choices=add_blank_choice(VLANQinQRoleChoices),
432 required=False
433 )
434 qinq_svlan = DynamicModelChoiceField(
435 label=_('Q-in-Q SVLAN'),
436 queryset=VLAN.objects.all(),
437 required=False,
438 query_params={
439 'qinq_role': VLANQinQRoleChoices.ROLE_SERVICE,
440 }
441 )
443 model = VLAN
444 fieldsets = (
445 FieldSet('status', 'role', 'tenant', 'description'),
446 FieldSet('qinq_role', 'qinq_svlan', name=_('Q-in-Q')),
447 FieldSet('region', 'site_group', 'site', 'group', name=_('Site & Group')),
448 )
449 nullable_fields = (
450 'site', 'group', 'tenant', 'role', 'description', 'qinq_role', 'qinq_svlan', 'comments',
451 )
454class VLANTranslationPolicyBulkEditForm(PrimaryModelBulkEditForm):
455 model = VLANTranslationPolicy
456 fieldsets = (
457 FieldSet('description'),
458 )
459 nullable_fields = ('description',)
462class VLANTranslationRuleBulkEditForm(NetBoxModelBulkEditForm):
463 policy = DynamicModelChoiceField(
464 label=_('Policy'),
465 queryset=VLANTranslationPolicy.objects.all(),
466 selector=True
467 )
468 local_vid = forms.IntegerField(required=False)
469 remote_vid = forms.IntegerField(required=False)
471 model = VLANTranslationRule
472 fieldsets = (
473 FieldSet('policy', 'local_vid', 'remote_vid'),
474 )
475 fields = ('policy', 'local_vid', 'remote_vid')
478class ServiceTemplateBulkEditForm(PrimaryModelBulkEditForm):
479 add_port_mappings = PortMappingField(
480 label=_('Add port mappings'),
481 required=False,
482 help_text=_("Port mappings to add to each selected object"),
483 )
484 remove_port_mappings = PortMappingField(
485 label=_('Remove port mappings'),
486 required=False,
487 help_text=_("Port mappings to remove from each selected object (if present)"),
488 )
490 model = ServiceTemplate
491 fieldsets = (
492 FieldSet('add_port_mappings', 'remove_port_mappings', 'description'),
493 )
494 nullable_fields = ('description', 'comments')
497class ServiceBulkEditForm(ServiceTemplateBulkEditForm):
498 model = Service