mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Tag filter field for filter forms
This commit is contained in:
@ -6,8 +6,8 @@ from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEdit
|
||||
from tenancy.forms import TenancyFilterForm, TenancyForm
|
||||
from tenancy.models import Tenant
|
||||
from utilities.forms import (
|
||||
APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField,
|
||||
DatePicker, FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
|
||||
APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField, DatePicker,
|
||||
FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField
|
||||
)
|
||||
from .constants import *
|
||||
from .models import Circuit, CircuitTermination, CircuitType, Provider
|
||||
@ -129,6 +129,10 @@ class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
label='ASN'
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Circuit types
|
||||
@ -333,6 +337,10 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm
|
||||
label='Commit rate (Kbps)'
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Circuit terminations
|
||||
|
@ -23,7 +23,8 @@ from utilities.forms import (
|
||||
APISelect, APISelectMultiple, add_blank_choice, ArrayFieldSelectMultiple, BootstrapMixin, BulkEditForm,
|
||||
BulkEditNullBooleanSelect, ChainedFieldsMixin, ChainedModelChoiceField, ColorSelect, CommentField, ComponentForm,
|
||||
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, FlexibleModelChoiceField, JSONField,
|
||||
SelectWithPK, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES
|
||||
SelectWithPK, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField,
|
||||
BOOLEAN_WITH_BLANK_CHOICES
|
||||
)
|
||||
from virtualization.models import Cluster, ClusterGroup
|
||||
from .constants import *
|
||||
@ -335,6 +336,10 @@ class SiteFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Rack groups
|
||||
@ -713,6 +718,10 @@ class RackFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Rack elevations
|
||||
@ -1005,6 +1014,10 @@ class DeviceTypeFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Device component templates
|
||||
@ -1947,6 +1960,10 @@ class DeviceFilterForm(BootstrapMixin, LocalConfigContextFilterForm, TenancyFilt
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Bulk device component creation
|
||||
@ -3405,6 +3422,10 @@ class InventoryItemFilterForm(BootstrapMixin, forms.Form):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Virtual chassis
|
||||
@ -3591,6 +3612,10 @@ class VirtualChassisFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Power panels
|
||||
@ -3967,3 +3992,7 @@ class PowerFeedFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
max_utilization = forms.IntegerField(
|
||||
required=False
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
@ -10,7 +10,7 @@ from tenancy.models import Tenant
|
||||
from utilities.forms import (
|
||||
add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditNullBooleanSelect, ChainedModelChoiceField,
|
||||
CSVChoiceField, DatePicker, ExpandableIPAddressField, FilterChoiceField, FlexibleModelChoiceField, ReturnURLForm,
|
||||
SlugField, StaticSelect2, StaticSelect2Multiple, BOOLEAN_WITH_BLANK_CHOICES
|
||||
SlugField, StaticSelect2, StaticSelect2Multiple, TagFilterField, BOOLEAN_WITH_BLANK_CHOICES
|
||||
)
|
||||
from virtualization.models import VirtualMachine
|
||||
from .constants import *
|
||||
@ -103,6 +103,10 @@ class VRFFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
label='Search'
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# RIRs
|
||||
@ -232,6 +236,10 @@ class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Roles
|
||||
@ -578,6 +586,10 @@ class PrefixFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm)
|
||||
label='Expand prefix hierarchy'
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# IP addresses
|
||||
@ -1006,6 +1018,10 @@ class IPAddressFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterFo
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# VLAN groups
|
||||
@ -1293,6 +1309,10 @@ class VLANFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Services
|
||||
@ -1353,6 +1373,10 @@ class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
required=False,
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
|
||||
pk = forms.ModelMultipleChoiceField(
|
||||
|
@ -7,7 +7,7 @@ from dcim.models import Device
|
||||
from extras.forms import AddRemoveTagsForm, CustomFieldBulkEditForm, CustomFieldFilterForm, CustomFieldForm
|
||||
from utilities.forms import (
|
||||
APISelect, APISelectMultiple, BootstrapMixin, FilterChoiceField, FlexibleModelChoiceField, SlugField,
|
||||
StaticSelect2Multiple
|
||||
StaticSelect2Multiple, TagFilterField
|
||||
)
|
||||
from .models import Secret, SecretRole, UserKey
|
||||
|
||||
@ -185,6 +185,10 @@ class SecretFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# UserKeys
|
||||
|
@ -4,7 +4,7 @@ from taggit.forms import TagField
|
||||
from extras.forms import AddRemoveTagsForm, CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||
from utilities.forms import (
|
||||
APISelect, APISelectMultiple, BootstrapMixin, ChainedFieldsMixin, ChainedModelChoiceField, CommentField,
|
||||
FilterChoiceField, SlugField,
|
||||
FilterChoiceField, SlugField, TagFilterField
|
||||
)
|
||||
from .models import Tenant, TenantGroup
|
||||
|
||||
@ -114,6 +114,10 @@ class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# Form extensions
|
||||
|
@ -6,6 +6,7 @@ from io import StringIO
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
from django.contrib.postgres.forms.jsonb import JSONField as _JSONField, InvalidJSONInput
|
||||
from django.db.models import Count
|
||||
from mptt.forms import TreeNodeMultipleChoiceField
|
||||
|
||||
from .constants import *
|
||||
@ -596,6 +597,22 @@ class SlugField(forms.SlugField):
|
||||
self.widget.attrs['slug-source'] = slug_source
|
||||
|
||||
|
||||
class TagFilterField(forms.MultipleChoiceField):
|
||||
"""
|
||||
A filter field for the tags of a model. Only the tags used by a model are displayed.
|
||||
|
||||
:param model: The model of the filter
|
||||
"""
|
||||
widget = StaticSelect2Multiple
|
||||
|
||||
def __init__(self, model, *args, **kwargs):
|
||||
if hasattr(model, 'tags'):
|
||||
tags = model.tags.annotate(count=Count('extras_taggeditem_items')).order_by('name')
|
||||
choices = [(str(tag.slug), '{} ({})'.format(tag.name, tag.count)) for tag in tags]
|
||||
|
||||
super().__init__(label='Tags', choices=choices, required=False, *args, **kwargs)
|
||||
|
||||
|
||||
class FilterChoiceIterator(forms.models.ModelChoiceIterator):
|
||||
|
||||
def __iter__(self):
|
||||
|
@ -13,7 +13,7 @@ from utilities.forms import (
|
||||
add_blank_choice, APISelect, APISelectMultiple, BootstrapMixin, BulkEditForm, BulkEditNullBooleanSelect,
|
||||
ChainedFieldsMixin, ChainedModelChoiceField, ChainedModelMultipleChoiceField, CommentField, ComponentForm,
|
||||
ConfirmationForm, CSVChoiceField, ExpandableNameField, FilterChoiceField, JSONField, SlugField,
|
||||
SmallTextarea, StaticSelect2, StaticSelect2Multiple
|
||||
SmallTextarea, StaticSelect2, StaticSelect2Multiple, TagFilterField
|
||||
)
|
||||
from .constants import *
|
||||
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||
@ -217,6 +217,10 @@ class ClusterFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||
)
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
class ClusterAddDevicesForm(BootstrapMixin, ChainedFieldsMixin, forms.Form):
|
||||
region = forms.ModelChoiceField(
|
||||
@ -623,6 +627,10 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil
|
||||
label='MAC address'
|
||||
)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
self.fields['tag'] = TagFilterField(self.model)
|
||||
|
||||
|
||||
#
|
||||
# VM interfaces
|
||||
|
Reference in New Issue
Block a user