Coverage for netbox/forms/bulk_edit.py: 72%
36 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.utils.translation import gettext_lazy as _
4from core.models import ObjectType
5from extras.choices import *
6from extras.models import Tag
7from utilities.forms import BulkEditForm
8from utilities.forms.fields import CommentField, DynamicModelMultipleChoiceField
10from .mixins import ChangelogMessageMixin, CustomFieldsMixin, OwnerMixin
12__all__ = (
13 'NestedGroupModelBulkEditForm',
14 'NetBoxModelBulkEditForm',
15 'OrganizationalModelBulkEditForm',
16 'PrimaryModelBulkEditForm',
17)
20class NetBoxModelBulkEditForm(ChangelogMessageMixin, CustomFieldsMixin, BulkEditForm):
21 """
22 Base form for modifying multiple NetBox objects (of the same type) in bulk via the UI. Adds support for custom
23 fields and adding/removing tags.
25 Attributes:
26 fieldsets: An iterable of two-tuples which define a heading and field set to display per section of
27 the rendered form (optional). If not defined, the all fields will be rendered as a single section.
28 """
29 fieldsets = None
31 pk = forms.ModelMultipleChoiceField(
32 queryset=None, # Set from self.model on init
33 widget=forms.MultipleHiddenInput
34 )
35 add_tags = DynamicModelMultipleChoiceField(
36 label=_('Add tags'),
37 queryset=Tag.objects.all(),
38 required=False
39 )
40 remove_tags = DynamicModelMultipleChoiceField(
41 label=_('Remove tags'),
42 queryset=Tag.objects.all(),
43 required=False
44 )
46 def __init__(self, *args, **kwargs):
47 super().__init__(*args, **kwargs)
49 self.fields['pk'].queryset = self.model.objects.all()
51 # Restrict tag fields by model
52 object_type = ObjectType.objects.get_for_model(self.model)
53 self.fields['add_tags'].widget.add_query_param('for_object_type_id', object_type.pk)
54 self.fields['remove_tags'].widget.add_query_param('for_object_type_id', object_type.pk)
56 self._extend_nullable_fields()
58 def _get_form_field(self, customfield):
59 return customfield.to_form_field(set_initial=False, enforce_required=False)
61 def _extend_nullable_fields(self):
62 # The bulk edit template always renders a Set Null control for these
63 nullable_common_fields = [
64 name for name in ('owner', 'comments')
65 if name in self.fields and name not in self.nullable_fields
66 ]
67 nullable_custom_fields = [
68 name for name, customfield in self.custom_fields.items()
69 if (not customfield.required and customfield.ui_editable == CustomFieldUIEditableChoices.YES)
70 ]
71 self.nullable_fields = (
72 *self.nullable_fields,
73 *nullable_common_fields,
74 *nullable_custom_fields,
75 )
78class PrimaryModelBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
79 """
80 Bulk edit form for models which inherit from PrimaryModel.
81 """
82 description = forms.CharField(
83 label=_('Description'),
84 max_length=100,
85 required=False
86 )
87 comments = CommentField()
90class OrganizationalModelBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
91 """
92 Bulk edit form for models which inherit from OrganizationalModel.
93 """
94 description = forms.CharField(
95 label=_('Description'),
96 max_length=200,
97 required=False
98 )
99 comments = CommentField()
102class NestedGroupModelBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
103 """
104 Bulk edit form for models which inherit from NestedGroupModel.
105 """
106 description = forms.CharField(
107 label=_('Description'),
108 max_length=200,
109 required=False
110 )
111 comments = CommentField()