mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 09:28:38 -06:00
Added custom field support to filter forms
This commit is contained in:
parent
28b9dda55d
commit
74a5960992
@ -2,7 +2,7 @@ from django import forms
|
|||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
|
||||||
from dcim.models import Site, Device, Interface, Rack, IFACE_FF_VIRTUAL
|
from dcim.models import Site, Device, Interface, Rack, IFACE_FF_VIRTUAL
|
||||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm
|
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||||
from tenancy.forms import bulkedit_tenant_choices
|
from tenancy.forms import bulkedit_tenant_choices
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
@ -62,7 +62,8 @@ def provider_site_choices():
|
|||||||
return [(s.slug, s.name) for s in site_choices]
|
return [(s.slug, s.name) for s in site_choices]
|
||||||
|
|
||||||
|
|
||||||
class ProviderFilterForm(forms.Form, BootstrapMixin):
|
class ProviderFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = Provider
|
||||||
site = forms.MultipleChoiceField(required=False, choices=provider_site_choices,
|
site = forms.MultipleChoiceField(required=False, choices=provider_site_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
|
|
||||||
@ -208,7 +209,8 @@ def circuit_site_choices():
|
|||||||
return [(s.slug, u'{} ({})'.format(s.name, s.circuit_count)) for s in site_choices]
|
return [(s.slug, u'{} ({})'.format(s.name, s.circuit_count)) for s in site_choices]
|
||||||
|
|
||||||
|
|
||||||
class CircuitFilterForm(forms.Form, BootstrapMixin):
|
class CircuitFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = Circuit
|
||||||
type = forms.MultipleChoiceField(required=False, choices=circuit_type_choices)
|
type = forms.MultipleChoiceField(required=False, choices=circuit_type_choices)
|
||||||
provider = forms.MultipleChoiceField(required=False, choices=circuit_provider_choices,
|
provider = forms.MultipleChoiceField(required=False, choices=circuit_provider_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
|
@ -3,7 +3,7 @@ import re
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models import Count, Q
|
from django.db.models import Count, Q
|
||||||
|
|
||||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm
|
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||||
from ipam.models import IPAddress
|
from ipam.models import IPAddress
|
||||||
from tenancy.forms import bulkedit_tenant_choices
|
from tenancy.forms import bulkedit_tenant_choices
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
@ -122,7 +122,8 @@ def site_tenant_choices():
|
|||||||
return [(t.slug, u'{} ({})'.format(t.name, t.site_count)) for t in tenant_choices]
|
return [(t.slug, u'{} ({})'.format(t.name, t.site_count)) for t in tenant_choices]
|
||||||
|
|
||||||
|
|
||||||
class SiteFilterForm(forms.Form, BootstrapMixin):
|
class SiteFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = Site
|
||||||
tenant = forms.MultipleChoiceField(required=False, choices=site_tenant_choices,
|
tenant = forms.MultipleChoiceField(required=False, choices=site_tenant_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
|
|
||||||
@ -273,7 +274,8 @@ def rack_role_choices():
|
|||||||
return [(r.slug, u'{} ({})'.format(r.name, r.rack_count)) for r in role_choices]
|
return [(r.slug, u'{} ({})'.format(r.name, r.rack_count)) for r in role_choices]
|
||||||
|
|
||||||
|
|
||||||
class RackFilterForm(forms.Form, BootstrapMixin):
|
class RackFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = Rack
|
||||||
site = forms.MultipleChoiceField(required=False, choices=rack_site_choices,
|
site = forms.MultipleChoiceField(required=False, choices=rack_site_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, label='Rack Group',
|
group_id = forms.MultipleChoiceField(required=False, choices=rack_group_choices, label='Rack Group',
|
||||||
@ -655,7 +657,8 @@ def device_platform_choices():
|
|||||||
return [(p.slug, u'{} ({})'.format(p.name, p.device_count)) for p in platform_choices]
|
return [(p.slug, u'{} ({})'.format(p.name, p.device_count)) for p in platform_choices]
|
||||||
|
|
||||||
|
|
||||||
class DeviceFilterForm(forms.Form, BootstrapMixin):
|
class DeviceFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = Device
|
||||||
site = forms.MultipleChoiceField(required=False, choices=device_site_choices,
|
site = forms.MultipleChoiceField(required=False, choices=device_site_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
rack_group_id = forms.MultipleChoiceField(required=False, choices=device_rack_group_choices, label='Rack Group',
|
rack_group_id = forms.MultipleChoiceField(required=False, choices=device_rack_group_choices, label='Rack Group',
|
||||||
|
@ -11,6 +11,8 @@ class CustomFieldFilter(django_filters.Filter):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def filter(self, queryset, value):
|
def filter(self, queryset, value):
|
||||||
|
if not value.strip():
|
||||||
|
return queryset
|
||||||
return queryset.filter(
|
return queryset.filter(
|
||||||
custom_field_values__field__name=self.name,
|
custom_field_values__field__name=self.name,
|
||||||
custom_field_values__serialized_value=value,
|
custom_field_values__serialized_value=value,
|
||||||
|
@ -4,7 +4,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from .models import CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CustomField, CustomFieldValue
|
from .models import CF_TYPE_BOOLEAN, CF_TYPE_DATE, CF_TYPE_INTEGER, CF_TYPE_SELECT, CustomField, CustomFieldValue
|
||||||
|
|
||||||
|
|
||||||
def get_custom_fields_for_model(content_type, bulk_editing=False):
|
def get_custom_fields_for_model(content_type, select_empty=False, select_none=True):
|
||||||
"""
|
"""
|
||||||
Retrieve all CustomFields applicable to the given ContentType
|
Retrieve all CustomFields applicable to the given ContentType
|
||||||
"""
|
"""
|
||||||
@ -41,9 +41,9 @@ def get_custom_fields_for_model(content_type, bulk_editing=False):
|
|||||||
# Select
|
# Select
|
||||||
elif cf.type == CF_TYPE_SELECT:
|
elif cf.type == CF_TYPE_SELECT:
|
||||||
choices = [(cfc.pk, cfc) for cfc in cf.choices.all()]
|
choices = [(cfc.pk, cfc) for cfc in cf.choices.all()]
|
||||||
if not cf.required:
|
if select_none and not cf.required:
|
||||||
choices = [(0, 'None')] + choices
|
choices = [(0, 'None')] + choices
|
||||||
if bulk_editing:
|
if select_empty:
|
||||||
choices = [(None, '---------')] + choices
|
choices = [(None, '---------')] + choices
|
||||||
field = forms.TypedChoiceField(choices=choices, coerce=int, required=cf.required)
|
field = forms.TypedChoiceField(choices=choices, coerce=int, required=cf.required)
|
||||||
else:
|
else:
|
||||||
@ -125,8 +125,24 @@ class CustomFieldBulkEditForm(forms.Form):
|
|||||||
|
|
||||||
# Add all applicable CustomFields to the form
|
# Add all applicable CustomFields to the form
|
||||||
custom_fields = []
|
custom_fields = []
|
||||||
for name, field in get_custom_fields_for_model(self.obj_type, bulk_editing=True).items():
|
for name, field in get_custom_fields_for_model(self.obj_type, select_empty=True).items():
|
||||||
field.required = False
|
field.required = False
|
||||||
self.fields[name] = field
|
self.fields[name] = field
|
||||||
custom_fields.append(name)
|
custom_fields.append(name)
|
||||||
self.custom_fields = custom_fields
|
self.custom_fields = custom_fields
|
||||||
|
|
||||||
|
|
||||||
|
class CustomFieldFilterForm(forms.Form):
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
self.obj_type = ContentType.objects.get_for_model(self.model)
|
||||||
|
|
||||||
|
super(CustomFieldFilterForm, self).__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Add all applicable CustomFields to the form
|
||||||
|
custom_fields = get_custom_fields_for_model(self.obj_type, select_empty=True, select_none=False)\
|
||||||
|
.items()
|
||||||
|
for name, field in custom_fields:
|
||||||
|
field.required = False
|
||||||
|
self.fields[name] = field
|
||||||
|
@ -2,7 +2,7 @@ from django import forms
|
|||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
|
||||||
from dcim.models import Site, Device, Interface
|
from dcim.models import Site, Device, Interface
|
||||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm
|
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||||
from tenancy.forms import bulkedit_tenant_choices
|
from tenancy.forms import bulkedit_tenant_choices
|
||||||
from tenancy.models import Tenant
|
from tenancy.models import Tenant
|
||||||
from utilities.forms import BootstrapMixin, APISelect, Livesearch, CSVDataField, BulkImportForm, SlugField
|
from utilities.forms import BootstrapMixin, APISelect, Livesearch, CSVDataField, BulkImportForm, SlugField
|
||||||
@ -69,7 +69,8 @@ def vrf_tenant_choices():
|
|||||||
return [(t.slug, u'{} ({})'.format(t.name, t.vrf_count)) for t in tenant_choices]
|
return [(t.slug, u'{} ({})'.format(t.name, t.vrf_count)) for t in tenant_choices]
|
||||||
|
|
||||||
|
|
||||||
class VRFFilterForm(forms.Form, BootstrapMixin):
|
class VRFFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = VRF
|
||||||
tenant = forms.MultipleChoiceField(required=False, choices=vrf_tenant_choices,
|
tenant = forms.MultipleChoiceField(required=False, choices=vrf_tenant_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
|
|
||||||
@ -127,7 +128,8 @@ def aggregate_rir_choices():
|
|||||||
return [(r.slug, u'{} ({})'.format(r.name, r.aggregate_count)) for r in rir_choices]
|
return [(r.slug, u'{} ({})'.format(r.name, r.aggregate_count)) for r in rir_choices]
|
||||||
|
|
||||||
|
|
||||||
class AggregateFilterForm(forms.Form, BootstrapMixin):
|
class AggregateFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = Aggregate
|
||||||
rir = forms.MultipleChoiceField(required=False, choices=aggregate_rir_choices, label='RIR',
|
rir = forms.MultipleChoiceField(required=False, choices=aggregate_rir_choices, label='RIR',
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
|
|
||||||
@ -287,7 +289,8 @@ def prefix_role_choices():
|
|||||||
return [(r.slug, u'{} ({})'.format(r.name, r.prefix_count)) for r in role_choices]
|
return [(r.slug, u'{} ({})'.format(r.name, r.prefix_count)) for r in role_choices]
|
||||||
|
|
||||||
|
|
||||||
class PrefixFilterForm(forms.Form, BootstrapMixin):
|
class PrefixFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = Prefix
|
||||||
parent = forms.CharField(required=False, label='Search Within', widget=forms.TextInput(attrs={
|
parent = forms.CharField(required=False, label='Search Within', widget=forms.TextInput(attrs={
|
||||||
'placeholder': 'Network',
|
'placeholder': 'Network',
|
||||||
}))
|
}))
|
||||||
@ -440,7 +443,8 @@ def ipaddress_vrf_choices():
|
|||||||
return [(v.pk, u'{} ({})'.format(v.name, v.ipaddress_count)) for v in vrf_choices]
|
return [(v.pk, u'{} ({})'.format(v.name, v.ipaddress_count)) for v in vrf_choices]
|
||||||
|
|
||||||
|
|
||||||
class IPAddressFilterForm(forms.Form, BootstrapMixin):
|
class IPAddressFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = IPAddress
|
||||||
parent = forms.CharField(required=False, label='Search Within', widget=forms.TextInput(attrs={
|
parent = forms.CharField(required=False, label='Search Within', widget=forms.TextInput(attrs={
|
||||||
'placeholder': 'Prefix',
|
'placeholder': 'Prefix',
|
||||||
}))
|
}))
|
||||||
@ -575,7 +579,8 @@ def vlan_role_choices():
|
|||||||
return [(r.slug, u'{} ({})'.format(r.name, r.vlan_count)) for r in role_choices]
|
return [(r.slug, u'{} ({})'.format(r.name, r.vlan_count)) for r in role_choices]
|
||||||
|
|
||||||
|
|
||||||
class VLANFilterForm(forms.Form, BootstrapMixin):
|
class VLANFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = VLAN
|
||||||
site = forms.MultipleChoiceField(required=False, choices=vlan_site_choices,
|
site = forms.MultipleChoiceField(required=False, choices=vlan_site_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
group_id = forms.MultipleChoiceField(required=False, choices=vlan_group_choices, label='VLAN Group',
|
group_id = forms.MultipleChoiceField(required=False, choices=vlan_group_choices, label='VLAN Group',
|
||||||
|
@ -1,27 +1,32 @@
|
|||||||
{% load form_helpers %}
|
{% load form_helpers %}
|
||||||
|
|
||||||
<div class="panel panel-default">
|
{% if filter_form %}
|
||||||
<div class="panel-heading">
|
<div class="panel panel-default">
|
||||||
<span class="fa fa-filter" aria-hidden="true"></span>
|
<div class="panel-heading">
|
||||||
<strong>Filter</strong>
|
<span class="fa fa-filter" aria-hidden="true"></span>
|
||||||
</div>
|
<strong>Filter</strong>
|
||||||
<div class="panel-body">
|
</div>
|
||||||
<form action="." method="get" class="form">
|
<div class="panel-body">
|
||||||
{% for field in filter_form %}
|
<form action="." method="get" class="form">
|
||||||
<div class="form-group">
|
{% for field in filter_form %}
|
||||||
{% if field|widget_type == 'checkboxinput' %}
|
<div class="form-group">
|
||||||
<label for="{{ field.id_for_label }}">{{ field }} {{ field.label }}</label>
|
{% if field|widget_type == 'checkboxinput' %}
|
||||||
{% else %}
|
<label for="{{ field.id_for_label }}">{{ field }} {{ field.label }}</label>
|
||||||
{{ field.label_tag }}
|
{% else %}
|
||||||
{{ field }}
|
{{ field.label_tag }}
|
||||||
{% endif %}
|
{{ field }}
|
||||||
|
{% endif %}
|
||||||
|
</div>
|
||||||
|
{% endfor %}
|
||||||
|
<div class="text-right">
|
||||||
|
<button type="submit" class="btn btn-primary">
|
||||||
|
<span class="fa fa-search" aria-hidden="true"></span> Apply
|
||||||
|
</button>
|
||||||
|
<a href="." class="btn btn-default">
|
||||||
|
<span class="fa fa-remove" aria-hidden="true"></span> Clear
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{% endfor %}
|
</form>
|
||||||
<div class="text-right">
|
</div>
|
||||||
<button type="submit" class="btn btn-primary">
|
|
||||||
<span class="fa fa-search" aria-hidden="true"></span> Apply filters
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
{% endif %}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models import Count
|
from django.db.models import Count
|
||||||
|
|
||||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm
|
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||||
from utilities.forms import BootstrapMixin, BulkImportForm, CommentField, CSVDataField, SlugField
|
from utilities.forms import BootstrapMixin, BulkImportForm, CommentField, CSVDataField, SlugField
|
||||||
|
|
||||||
from .models import Tenant, TenantGroup
|
from .models import Tenant, TenantGroup
|
||||||
@ -79,6 +79,7 @@ def tenant_group_choices():
|
|||||||
return [(g.slug, u'{} ({})'.format(g.name, g.tenant_count)) for g in group_choices]
|
return [(g.slug, u'{} ({})'.format(g.name, g.tenant_count)) for g in group_choices]
|
||||||
|
|
||||||
|
|
||||||
class TenantFilterForm(forms.Form, BootstrapMixin):
|
class TenantFilterForm(BootstrapMixin, CustomFieldFilterForm):
|
||||||
|
model = Tenant
|
||||||
group = forms.MultipleChoiceField(required=False, choices=tenant_group_choices,
|
group = forms.MultipleChoiceField(required=False, choices=tenant_group_choices,
|
||||||
widget=forms.SelectMultiple(attrs={'size': 8}))
|
widget=forms.SelectMultiple(attrs={'size': 8}))
|
||||||
|
Loading…
Reference in New Issue
Block a user