mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-24 09:28:38 -06:00
Merge pull request #15369 from netbox-community/15237-audit-filtersets
Closes #15237: Add tests for missing filters
This commit is contained in:
commit
2d4295e2ed
@ -67,7 +67,7 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Provider
|
model = Provider
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -95,7 +95,7 @@ class ProviderAccountFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ProviderAccount
|
model = ProviderAccount
|
||||||
fields = ['id', 'name', 'account', 'description']
|
fields = ('id', 'name', 'account', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -122,7 +122,7 @@ class ProviderNetworkFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ProviderNetwork
|
model = ProviderNetwork
|
||||||
fields = ['id', 'name', 'service_id', 'description']
|
fields = ('id', 'name', 'service_id', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -139,7 +139,7 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitType
|
model = CircuitType
|
||||||
fields = ['id', 'name', 'slug', 'color', 'description']
|
fields = ('id', 'name', 'slug', 'color', 'description')
|
||||||
|
|
||||||
|
|
||||||
class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
|
class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
|
||||||
@ -158,6 +158,12 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
|
|||||||
queryset=ProviderAccount.objects.all(),
|
queryset=ProviderAccount.objects.all(),
|
||||||
label=_('Provider account (ID)'),
|
label=_('Provider account (ID)'),
|
||||||
)
|
)
|
||||||
|
provider_account = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='provider_account__account',
|
||||||
|
queryset=Provider.objects.all(),
|
||||||
|
to_field_name='account',
|
||||||
|
label=_('Provider account (account)'),
|
||||||
|
)
|
||||||
provider_network_id = django_filters.ModelMultipleChoiceFilter(
|
provider_network_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='terminations__provider_network',
|
field_name='terminations__provider_network',
|
||||||
queryset=ProviderNetwork.objects.all(),
|
queryset=ProviderNetwork.objects.all(),
|
||||||
@ -214,10 +220,18 @@ class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label=_('Site (slug)'),
|
label=_('Site (slug)'),
|
||||||
)
|
)
|
||||||
|
termination_a_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=CircuitTermination.objects.all(),
|
||||||
|
label=_('Termination A (ID)'),
|
||||||
|
)
|
||||||
|
termination_z_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=CircuitTermination.objects.all(),
|
||||||
|
label=_('Termination A (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Circuit
|
model = Circuit
|
||||||
fields = ['id', 'cid', 'description', 'install_date', 'termination_date', 'commit_rate']
|
fields = ('id', 'cid', 'description', 'install_date', 'termination_date', 'commit_rate')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -258,7 +272,10 @@ class CircuitTerminationFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CircuitTermination
|
model = CircuitTermination
|
||||||
fields = ['id', 'term_side', 'port_speed', 'upstream_speed', 'xconnect_id', 'description', 'cable_end']
|
fields = (
|
||||||
|
'id', 'term_side', 'port_speed', 'upstream_speed', 'xconnect_id', 'description', 'mark_connected',
|
||||||
|
'pp_info', 'cable_end',
|
||||||
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -330,6 +330,7 @@ class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class CircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class CircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = CircuitTermination.objects.all()
|
queryset = CircuitTermination.objects.all()
|
||||||
filterset = CircuitTerminationFilterSet
|
filterset = CircuitTerminationFilterSet
|
||||||
|
ignore_fields = ('cable',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -28,7 +28,7 @@ class DataSourceFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DataSource
|
model = DataSource
|
||||||
fields = ('id', 'name', 'enabled', 'description')
|
fields = ('id', 'name', 'enabled', 'description', 'source_url', 'last_synced')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -115,7 +115,7 @@ class JobFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Job
|
model = Job
|
||||||
fields = ('id', 'object_type', 'object_id', 'name', 'interval', 'status', 'user')
|
fields = ('id', 'object_type', 'object_id', 'name', 'interval', 'status', 'user', 'job_id')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -134,9 +134,7 @@ class ConfigRevisionFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConfigRevision
|
model = ConfigRevision
|
||||||
fields = [
|
fields = ('id', 'created', 'comment')
|
||||||
'id',
|
|
||||||
]
|
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -10,6 +10,7 @@ from ..models import *
|
|||||||
class DataSourceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class DataSourceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = DataSource.objects.all()
|
queryset = DataSource.objects.all()
|
||||||
filterset = DataSourceFilterSet
|
filterset = DataSourceFilterSet
|
||||||
|
ignore_fields = ('ignore_rules', 'parameters')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -70,6 +71,7 @@ class DataSourceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class DataFileTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class DataFileTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = DataFile.objects.all()
|
queryset = DataFile.objects.all()
|
||||||
filterset = DataFileFilterSet
|
filterset = DataFileFilterSet
|
||||||
|
ignore_fields = ('data',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -18,11 +18,12 @@ from tenancy.models import *
|
|||||||
from utilities.choices import ColorChoices
|
from utilities.choices import ColorChoices
|
||||||
from utilities.filters import (
|
from utilities.filters import (
|
||||||
ContentTypeFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueWWNFilter,
|
ContentTypeFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueWWNFilter,
|
||||||
TreeNodeMultipleChoiceFilter,
|
NumericArrayFilter, TreeNodeMultipleChoiceFilter,
|
||||||
)
|
)
|
||||||
from virtualization.models import Cluster
|
from virtualization.models import Cluster
|
||||||
from vpn.models import L2VPN
|
from vpn.models import L2VPN
|
||||||
from wireless.choices import WirelessRoleChoices, WirelessChannelChoices
|
from wireless.choices import WirelessRoleChoices, WirelessChannelChoices
|
||||||
|
from wireless.models import WirelessLAN, WirelessLink
|
||||||
from .choices import *
|
from .choices import *
|
||||||
from .constants import *
|
from .constants import *
|
||||||
from .models import *
|
from .models import *
|
||||||
@ -105,7 +106,7 @@ class RegionFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Region
|
model = Region
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class SiteGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
|
class SiteGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
|
||||||
@ -135,7 +136,7 @@ class SiteGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SiteGroup
|
model = SiteGroup
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class SiteFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
|
class SiteFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
|
||||||
@ -178,12 +179,11 @@ class SiteFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe
|
|||||||
queryset=ASN.objects.all(),
|
queryset=ASN.objects.all(),
|
||||||
label=_('AS (ID)'),
|
label=_('AS (ID)'),
|
||||||
)
|
)
|
||||||
|
time_zone = MultiValueCharFilter()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Site
|
model = Site
|
||||||
fields = (
|
fields = ('id', 'name', 'slug', 'facility', 'latitude', 'longitude', 'description')
|
||||||
'id', 'name', 'slug', 'facility', 'latitude', 'longitude', 'description'
|
|
||||||
)
|
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -270,7 +270,7 @@ class LocationFilterSet(TenancyFilterSet, ContactModelFilterSet, OrganizationalM
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Location
|
model = Location
|
||||||
fields = ['id', 'name', 'slug', 'status', 'description']
|
fields = ('id', 'name', 'slug', 'status', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -285,7 +285,7 @@ class RackRoleFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackRole
|
model = RackRole
|
||||||
fields = ['id', 'name', 'slug', 'color', 'description']
|
fields = ('id', 'name', 'slug', 'color', 'description')
|
||||||
|
|
||||||
|
|
||||||
class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
|
class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
|
||||||
@ -364,10 +364,10 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Rack
|
model = Rack
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'name', 'facility_id', 'asset_tag', 'u_height', 'starting_unit', 'desc_units', 'outer_width',
|
'id', 'name', 'facility_id', 'asset_tag', 'u_height', 'starting_unit', 'desc_units', 'outer_width',
|
||||||
'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description',
|
'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description',
|
||||||
]
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -447,10 +447,14 @@ class RackReservationFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
to_field_name='username',
|
to_field_name='username',
|
||||||
label=_('User (name)'),
|
label=_('User (name)'),
|
||||||
)
|
)
|
||||||
|
unit = NumericArrayFilter(
|
||||||
|
field_name='units',
|
||||||
|
lookup_expr='contains'
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RackReservation
|
model = RackReservation
|
||||||
fields = ['id', 'created', 'description']
|
fields = ('id', 'created', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -467,7 +471,7 @@ class ManufacturerFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet)
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Manufacturer
|
model = Manufacturer
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class DeviceTypeFilterSet(NetBoxModelFilterSet):
|
class DeviceTypeFilterSet(NetBoxModelFilterSet):
|
||||||
@ -538,10 +542,22 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'model', 'slug', 'part_number', 'u_height', 'exclude_from_utilization', 'is_full_depth',
|
'id', 'model', 'slug', 'part_number', 'u_height', 'exclude_from_utilization', 'is_full_depth',
|
||||||
'subdevice_role', 'airflow', 'weight', 'weight_unit', 'description',
|
'subdevice_role', 'airflow', 'weight', 'weight_unit', 'description',
|
||||||
]
|
|
||||||
|
# Counters
|
||||||
|
'console_port_template_count',
|
||||||
|
'console_server_port_template_count',
|
||||||
|
'power_port_template_count',
|
||||||
|
'power_outlet_template_count',
|
||||||
|
'interface_template_count',
|
||||||
|
'front_port_template_count',
|
||||||
|
'rear_port_template_count',
|
||||||
|
'device_bay_template_count',
|
||||||
|
'module_bay_template_count',
|
||||||
|
'inventory_item_template_count',
|
||||||
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -635,7 +651,7 @@ class ModuleTypeFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleType
|
model = ModuleType
|
||||||
fields = ['id', 'model', 'part_number', 'weight', 'weight_unit', 'description']
|
fields = ('id', 'model', 'part_number', 'weight', 'weight_unit', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -675,12 +691,15 @@ class DeviceTypeComponentFilterSet(django_filters.FilterSet):
|
|||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
devicetype_id = django_filters.ModelMultipleChoiceFilter(
|
device_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
queryset=DeviceType.objects.all(),
|
queryset=DeviceType.objects.all(),
|
||||||
field_name='device_type_id',
|
field_name='device_type_id',
|
||||||
label=_('Device type (ID)'),
|
label=_('Device type (ID)'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Remove in v4.1
|
||||||
|
devicetype_id = device_type_id
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
return queryset
|
return queryset
|
||||||
@ -691,32 +710,35 @@ class DeviceTypeComponentFilterSet(django_filters.FilterSet):
|
|||||||
|
|
||||||
|
|
||||||
class ModularDeviceTypeComponentFilterSet(DeviceTypeComponentFilterSet):
|
class ModularDeviceTypeComponentFilterSet(DeviceTypeComponentFilterSet):
|
||||||
moduletype_id = django_filters.ModelMultipleChoiceFilter(
|
module_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
queryset=ModuleType.objects.all(),
|
queryset=ModuleType.objects.all(),
|
||||||
field_name='module_type_id',
|
field_name='module_type_id',
|
||||||
label=_('Module type (ID)'),
|
label=_('Module type (ID)'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Remove in v4.1
|
||||||
|
moduletype_id = module_type_id
|
||||||
|
|
||||||
|
|
||||||
class ConsolePortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
class ConsolePortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsolePortTemplate
|
model = ConsolePortTemplate
|
||||||
fields = ['id', 'name', 'type', 'description']
|
fields = ('id', 'name', 'label', 'type', 'description')
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
class ConsoleServerPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsoleServerPortTemplate
|
model = ConsoleServerPortTemplate
|
||||||
fields = ['id', 'name', 'type', 'description']
|
fields = ('id', 'name', 'label', 'type', 'description')
|
||||||
|
|
||||||
|
|
||||||
class PowerPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
class PowerPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPortTemplate
|
model = PowerPortTemplate
|
||||||
fields = ['id', 'name', 'type', 'maximum_draw', 'allocated_draw', 'description']
|
fields = ('id', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description')
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
class PowerOutletTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
||||||
@ -724,10 +746,14 @@ class PowerOutletTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceType
|
|||||||
choices=PowerOutletFeedLegChoices,
|
choices=PowerOutletFeedLegChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
)
|
)
|
||||||
|
power_port_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=PowerPortTemplate.objects.all(),
|
||||||
|
label=_('Power port (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutletTemplate
|
model = PowerOutletTemplate
|
||||||
fields = ['id', 'name', 'type', 'feed_leg', 'description']
|
fields = ('id', 'name', 'label', 'type', 'feed_leg', 'description')
|
||||||
|
|
||||||
|
|
||||||
class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
||||||
@ -751,7 +777,7 @@ class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeCo
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InterfaceTemplate
|
model = InterfaceTemplate
|
||||||
fields = ['id', 'name', 'type', 'enabled', 'mgmt_only', 'description']
|
fields = ('id', 'name', 'label', 'type', 'enabled', 'mgmt_only', 'description')
|
||||||
|
|
||||||
|
|
||||||
class FrontPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
class FrontPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
||||||
@ -759,10 +785,13 @@ class FrontPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeCo
|
|||||||
choices=PortTypeChoices,
|
choices=PortTypeChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
)
|
)
|
||||||
|
rear_port_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=RearPort.objects.all()
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FrontPortTemplate
|
model = FrontPortTemplate
|
||||||
fields = ['id', 'name', 'type', 'color', 'description']
|
fields = ('id', 'name', 'label', 'type', 'color', 'rear_port_position', 'description')
|
||||||
|
|
||||||
|
|
||||||
class RearPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
class RearPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeComponentFilterSet):
|
||||||
@ -773,21 +802,21 @@ class RearPortTemplateFilterSet(ChangeLoggedModelFilterSet, ModularDeviceTypeCom
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RearPortTemplate
|
model = RearPortTemplate
|
||||||
fields = ['id', 'name', 'type', 'color', 'positions', 'description']
|
fields = ('id', 'name', 'label', 'type', 'color', 'positions', 'description')
|
||||||
|
|
||||||
|
|
||||||
class ModuleBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
|
class ModuleBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBayTemplate
|
model = ModuleBayTemplate
|
||||||
fields = ['id', 'name', 'description']
|
fields = ('id', 'name', 'label', 'position', 'description')
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
|
class DeviceBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceBayTemplate
|
model = DeviceBayTemplate
|
||||||
fields = ['id', 'name', 'description']
|
fields = ('id', 'name', 'label', 'description')
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
|
class InventoryItemTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
|
||||||
@ -820,7 +849,7 @@ class InventoryItemTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeCompo
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventoryItemTemplate
|
model = InventoryItemTemplate
|
||||||
fields = ['id', 'name', 'label', 'part_id', 'description']
|
fields = ('id', 'name', 'label', 'part_id', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -841,7 +870,7 @@ class DeviceRoleFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceRole
|
model = DeviceRole
|
||||||
fields = ['id', 'name', 'slug', 'color', 'vm_role', 'description']
|
fields = ('id', 'name', 'slug', 'color', 'vm_role', 'description')
|
||||||
|
|
||||||
|
|
||||||
class PlatformFilterSet(OrganizationalModelFilterSet):
|
class PlatformFilterSet(OrganizationalModelFilterSet):
|
||||||
@ -867,7 +896,7 @@ class PlatformFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Platform
|
model = Platform
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
@extend_schema_field(OpenApiTypes.STR)
|
@extend_schema_field(OpenApiTypes.STR)
|
||||||
def get_for_device_type(self, queryset, name, value):
|
def get_for_device_type(self, queryset, name, value):
|
||||||
@ -979,6 +1008,11 @@ class DeviceFilterSet(
|
|||||||
queryset=Rack.objects.all(),
|
queryset=Rack.objects.all(),
|
||||||
label=_('Rack (ID)'),
|
label=_('Rack (ID)'),
|
||||||
)
|
)
|
||||||
|
parent_bay_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='parent_bay',
|
||||||
|
queryset=DeviceBay.objects.all(),
|
||||||
|
label=_('Parent bay (ID)'),
|
||||||
|
)
|
||||||
cluster_id = django_filters.ModelMultipleChoiceFilter(
|
cluster_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
queryset=Cluster.objects.all(),
|
queryset=Cluster.objects.all(),
|
||||||
label=_('VM cluster (ID)'),
|
label=_('VM cluster (ID)'),
|
||||||
@ -1068,10 +1102,22 @@ class DeviceFilterSet(
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Device
|
model = Device
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'asset_tag', 'face', 'position', 'latitude', 'longitude', 'airflow', 'vc_position', 'vc_priority',
|
'id', 'asset_tag', 'face', 'position', 'latitude', 'longitude', 'airflow', 'vc_position', 'vc_priority',
|
||||||
'description',
|
'description',
|
||||||
]
|
|
||||||
|
# Counters
|
||||||
|
'console_port_count',
|
||||||
|
'console_server_port_count',
|
||||||
|
'power_port_count',
|
||||||
|
'power_outlet_count',
|
||||||
|
'interface_count',
|
||||||
|
'front_port_count',
|
||||||
|
'rear_port_count',
|
||||||
|
'device_bay_count',
|
||||||
|
'module_bay_count',
|
||||||
|
'inventory_item_count',
|
||||||
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -1134,24 +1180,29 @@ class VirtualDeviceContextFilterSet(NetBoxModelFilterSet, TenancyFilterSet, Prim
|
|||||||
device_id = django_filters.ModelMultipleChoiceFilter(
|
device_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='device',
|
field_name='device',
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
label='VDC (ID)',
|
label=_('VDC (ID)')
|
||||||
)
|
)
|
||||||
device = django_filters.ModelMultipleChoiceFilter(
|
device = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='device',
|
field_name='device',
|
||||||
queryset=Device.objects.all(),
|
queryset=Device.objects.all(),
|
||||||
label='Device model',
|
label=_('Device model')
|
||||||
|
)
|
||||||
|
interface_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='interfaces',
|
||||||
|
queryset=Interface.objects.all(),
|
||||||
|
label=_('Interface (ID)')
|
||||||
)
|
)
|
||||||
status = django_filters.MultipleChoiceFilter(
|
status = django_filters.MultipleChoiceFilter(
|
||||||
choices=VirtualDeviceContextStatusChoices
|
choices=VirtualDeviceContextStatusChoices
|
||||||
)
|
)
|
||||||
has_primary_ip = django_filters.BooleanFilter(
|
has_primary_ip = django_filters.BooleanFilter(
|
||||||
method='_has_primary_ip',
|
method='_has_primary_ip',
|
||||||
label='Has a primary IP',
|
label=_('Has a primary IP')
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualDeviceContext
|
model = VirtualDeviceContext
|
||||||
fields = ['id', 'device', 'name', 'description']
|
fields = ('id', 'device', 'name', 'identifier', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -1217,7 +1268,7 @@ class ModuleFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Module
|
model = Module
|
||||||
fields = ['id', 'status', 'asset_tag', 'description']
|
fields = ('id', 'status', 'asset_tag', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -1361,6 +1412,10 @@ class ModularDeviceComponentFilterSet(DeviceComponentFilterSet):
|
|||||||
|
|
||||||
|
|
||||||
class CabledObjectFilterSet(django_filters.FilterSet):
|
class CabledObjectFilterSet(django_filters.FilterSet):
|
||||||
|
cable_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=Cable.objects.all(),
|
||||||
|
label=_('Cable (ID)'),
|
||||||
|
)
|
||||||
cabled = django_filters.BooleanFilter(
|
cabled = django_filters.BooleanFilter(
|
||||||
field_name='cable',
|
field_name='cable',
|
||||||
lookup_expr='isnull',
|
lookup_expr='isnull',
|
||||||
@ -1402,7 +1457,7 @@ class ConsolePortFilterSet(
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsolePort
|
model = ConsolePort
|
||||||
fields = ['id', 'name', 'label', 'description', 'cable_end']
|
fields = ('id', 'name', 'label', 'speed', 'description', 'mark_connected', 'cable_end')
|
||||||
|
|
||||||
|
|
||||||
class ConsoleServerPortFilterSet(
|
class ConsoleServerPortFilterSet(
|
||||||
@ -1418,7 +1473,7 @@ class ConsoleServerPortFilterSet(
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsoleServerPort
|
model = ConsoleServerPort
|
||||||
fields = ['id', 'name', 'label', 'description', 'cable_end']
|
fields = ('id', 'name', 'label', 'speed', 'description', 'mark_connected', 'cable_end')
|
||||||
|
|
||||||
|
|
||||||
class PowerPortFilterSet(
|
class PowerPortFilterSet(
|
||||||
@ -1434,7 +1489,9 @@ class PowerPortFilterSet(
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPort
|
model = PowerPort
|
||||||
fields = ['id', 'name', 'label', 'maximum_draw', 'allocated_draw', 'description', 'cable_end']
|
fields = (
|
||||||
|
'id', 'name', 'label', 'maximum_draw', 'allocated_draw', 'description', 'mark_connected', 'cable_end',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletFilterSet(
|
class PowerOutletFilterSet(
|
||||||
@ -1451,10 +1508,16 @@ class PowerOutletFilterSet(
|
|||||||
choices=PowerOutletFeedLegChoices,
|
choices=PowerOutletFeedLegChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
)
|
)
|
||||||
|
power_port_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=PowerPort.objects.all(),
|
||||||
|
label=_('Power port (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutlet
|
model = PowerOutlet
|
||||||
fields = ['id', 'name', 'label', 'feed_leg', 'description', 'cable_end']
|
fields = (
|
||||||
|
'id', 'name', 'label', 'feed_leg', 'description', 'mark_connected', 'cable_end',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class CommonInterfaceFilterSet(django_filters.FilterSet):
|
class CommonInterfaceFilterSet(django_filters.FilterSet):
|
||||||
@ -1569,27 +1632,37 @@ class InterfaceFilterSet(
|
|||||||
vdc_id = django_filters.ModelMultipleChoiceFilter(
|
vdc_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='vdcs',
|
field_name='vdcs',
|
||||||
queryset=VirtualDeviceContext.objects.all(),
|
queryset=VirtualDeviceContext.objects.all(),
|
||||||
label='Virtual Device Context',
|
label=_('Virtual Device Context')
|
||||||
)
|
)
|
||||||
vdc_identifier = django_filters.ModelMultipleChoiceFilter(
|
vdc_identifier = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='vdcs__identifier',
|
field_name='vdcs__identifier',
|
||||||
queryset=VirtualDeviceContext.objects.all(),
|
queryset=VirtualDeviceContext.objects.all(),
|
||||||
to_field_name='identifier',
|
to_field_name='identifier',
|
||||||
label='Virtual Device Context (Identifier)',
|
label=_('Virtual Device Context (Identifier)')
|
||||||
)
|
)
|
||||||
vdc = django_filters.ModelMultipleChoiceFilter(
|
vdc = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='vdcs__name',
|
field_name='vdcs__name',
|
||||||
queryset=VirtualDeviceContext.objects.all(),
|
queryset=VirtualDeviceContext.objects.all(),
|
||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
label='Virtual Device Context',
|
label=_('Virtual Device Context')
|
||||||
|
)
|
||||||
|
wireless_lan_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='wireless_lans',
|
||||||
|
queryset=WirelessLAN.objects.all(),
|
||||||
|
label=_('Wireless LAN')
|
||||||
|
)
|
||||||
|
wireless_link_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=WirelessLink.objects.all(),
|
||||||
|
label=_('Wireless link')
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Interface
|
model = Interface
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'name', 'label', 'type', 'enabled', 'mtu', 'mgmt_only', 'poe_mode', 'poe_type', 'mode', 'rf_role',
|
'id', 'name', 'label', 'type', 'enabled', 'mtu', 'mgmt_only', 'poe_mode', 'poe_type', 'mode', 'rf_role',
|
||||||
'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'cable_end',
|
'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'description', 'mark_connected',
|
||||||
]
|
'cable_id', 'cable_end',
|
||||||
|
)
|
||||||
|
|
||||||
def filter_virtual_chassis_member(self, queryset, name, value):
|
def filter_virtual_chassis_member(self, queryset, name, value):
|
||||||
try:
|
try:
|
||||||
@ -1618,10 +1691,15 @@ class FrontPortFilterSet(
|
|||||||
choices=PortTypeChoices,
|
choices=PortTypeChoices,
|
||||||
null_value=None
|
null_value=None
|
||||||
)
|
)
|
||||||
|
rear_port_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=RearPort.objects.all()
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FrontPort
|
model = FrontPort
|
||||||
fields = ['id', 'name', 'label', 'type', 'color', 'description', 'cable_end']
|
fields = (
|
||||||
|
'id', 'name', 'label', 'type', 'color', 'rear_port_position', 'description', 'mark_connected', 'cable_end',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class RearPortFilterSet(
|
class RearPortFilterSet(
|
||||||
@ -1636,21 +1714,38 @@ class RearPortFilterSet(
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RearPort
|
model = RearPort
|
||||||
fields = ['id', 'name', 'label', 'type', 'color', 'positions', 'description', 'cable_end']
|
fields = (
|
||||||
|
'id', 'name', 'label', 'type', 'color', 'positions', 'description', 'mark_connected', 'cable_end',
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ModuleBayFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
|
class ModuleBayFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
|
||||||
|
installed_module_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='installed_module',
|
||||||
|
queryset=ModuleBay.objects.all(),
|
||||||
|
label=_('Installed module (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ModuleBay
|
model = ModuleBay
|
||||||
fields = ['id', 'name', 'label', 'description']
|
fields = ('id', 'name', 'label', 'position', 'description')
|
||||||
|
|
||||||
|
|
||||||
class DeviceBayFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
|
class DeviceBayFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
|
||||||
|
installed_device_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=Device.objects.all(),
|
||||||
|
label=_('Installed device (ID)'),
|
||||||
|
)
|
||||||
|
installed_device = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='installed_device__name',
|
||||||
|
queryset=Device.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
label=_('Installed device (name)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = DeviceBay
|
model = DeviceBay
|
||||||
fields = ['id', 'name', 'label', 'description']
|
fields = ('id', 'name', 'label', 'description')
|
||||||
|
|
||||||
|
|
||||||
class InventoryItemFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
|
class InventoryItemFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
|
||||||
@ -1686,7 +1781,7 @@ class InventoryItemFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventoryItem
|
model = InventoryItem
|
||||||
fields = ['id', 'name', 'label', 'part_id', 'asset_tag', 'discovered']
|
fields = ('id', 'name', 'label', 'part_id', 'asset_tag', 'description', 'discovered')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -1705,7 +1800,7 @@ class InventoryItemRoleFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = InventoryItemRole
|
model = InventoryItemRole
|
||||||
fields = ['id', 'name', 'slug', 'color', 'description']
|
fields = ('id', 'name', 'slug', 'color', 'description')
|
||||||
|
|
||||||
|
|
||||||
class VirtualChassisFilterSet(NetBoxModelFilterSet):
|
class VirtualChassisFilterSet(NetBoxModelFilterSet):
|
||||||
@ -1770,7 +1865,7 @@ class VirtualChassisFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualChassis
|
model = VirtualChassis
|
||||||
fields = ['id', 'domain', 'name', 'description']
|
fields = ('id', 'domain', 'name', 'description', 'member_count')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -1875,7 +1970,7 @@ class CableFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cable
|
model = Cable
|
||||||
fields = ['id', 'label', 'length', 'length_unit', 'description']
|
fields = ('id', 'label', 'length', 'length_unit', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -1953,12 +2048,12 @@ class CableFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
|
|||||||
return self.filter_by_termination_object(queryset, CircuitTermination, value)
|
return self.filter_by_termination_object(queryset, CircuitTermination, value)
|
||||||
|
|
||||||
|
|
||||||
class CableTerminationFilterSet(BaseFilterSet):
|
class CableTerminationFilterSet(ChangeLoggedModelFilterSet):
|
||||||
termination_type = ContentTypeFilter()
|
termination_type = ContentTypeFilter()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CableTermination
|
model = CableTermination
|
||||||
fields = ['id', 'cable', 'cable_end', 'termination_type', 'termination_id']
|
fields = ('id', 'cable', 'cable_end', 'termination_type', 'termination_id')
|
||||||
|
|
||||||
|
|
||||||
class PowerPanelFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
class PowerPanelFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
||||||
@ -2007,7 +2102,7 @@ class PowerPanelFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPanel
|
model = PowerPanel
|
||||||
fields = ['id', 'name', 'description']
|
fields = ('id', 'name', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -2073,10 +2168,10 @@ class PowerFeedFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet, PathEndpoi
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerFeed
|
model = PowerFeed
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization', 'cable_end',
|
'id', 'name', 'status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization',
|
||||||
'description',
|
'available_power', 'mark_connected', 'cable_end', 'description',
|
||||||
]
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -2135,18 +2230,18 @@ class ConsoleConnectionFilterSet(ConnectionFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConsolePort
|
model = ConsolePort
|
||||||
fields = ['name']
|
fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
class PowerConnectionFilterSet(ConnectionFilterSet):
|
class PowerConnectionFilterSet(ConnectionFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerPort
|
model = PowerPort
|
||||||
fields = ['name']
|
fields = ('name',)
|
||||||
|
|
||||||
|
|
||||||
class InterfaceConnectionFilterSet(ConnectionFilterSet):
|
class InterfaceConnectionFilterSet(ConnectionFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Interface
|
model = Interface
|
||||||
fields = []
|
fields = tuple()
|
||||||
|
@ -754,7 +754,7 @@ class DeviceFilterForm(
|
|||||||
)
|
)
|
||||||
has_oob_ip = forms.NullBooleanField(
|
has_oob_ip = forms.NullBooleanField(
|
||||||
required=False,
|
required=False,
|
||||||
label='Has an OOB IP',
|
label=_('Has an OOB IP'),
|
||||||
widget=forms.Select(
|
widget=forms.Select(
|
||||||
choices=BOOLEAN_WITH_BLANK_CHOICES
|
choices=BOOLEAN_WITH_BLANK_CHOICES
|
||||||
)
|
)
|
||||||
|
@ -196,6 +196,7 @@ class SiteGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class SiteTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class SiteTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = Site.objects.all()
|
queryset = Site.objects.all()
|
||||||
filterset = SiteFilterSet
|
filterset = SiteFilterSet
|
||||||
|
ignore_fields = ('physical_address', 'shipping_address')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -467,6 +468,7 @@ class RackRoleTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = Rack.objects.all()
|
queryset = Rack.objects.all()
|
||||||
filterset = RackFilterSet
|
filterset = RackFilterSet
|
||||||
|
ignore_fields = ('units',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -726,6 +728,7 @@ class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class RackReservationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class RackReservationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = RackReservation.objects.all()
|
queryset = RackReservation.objects.all()
|
||||||
filterset = RackReservationFilterSet
|
filterset = RackReservationFilterSet
|
||||||
|
ignore_fields = ('units',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -889,6 +892,7 @@ class ManufacturerTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = DeviceType.objects.all()
|
queryset = DeviceType.objects.all()
|
||||||
filterset = DeviceTypeFilterSet
|
filterset = DeviceTypeFilterSet
|
||||||
|
ignore_fields = ('front_image', 'rear_image')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1880,6 +1884,7 @@ class PlatformTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = Device.objects.all()
|
queryset = Device.objects.all()
|
||||||
filterset = DeviceFilterSet
|
filterset = DeviceFilterSet
|
||||||
|
ignore_fields = ('local_context_data', 'oob_ip', 'primary_ip4', 'primary_ip6', 'vc_master_for')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -2332,6 +2337,7 @@ class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class ModuleTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = Module.objects.all()
|
queryset = Module.objects.all()
|
||||||
filterset = ModuleFilterSet
|
filterset = ModuleFilterSet
|
||||||
|
ignore_fields = ('local_context_data',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -3229,6 +3235,7 @@ class PowerOutletTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedF
|
|||||||
class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests):
|
class InterfaceTestCase(TestCase, DeviceComponentFilterSetTests, ChangeLoggedFilterSetTests):
|
||||||
queryset = Interface.objects.all()
|
queryset = Interface.objects.all()
|
||||||
filterset = InterfaceFilterSet
|
filterset = InterfaceFilterSet
|
||||||
|
ignore_fields = ('tagged_vlans', 'untagged_vlan', 'vdcs')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -5332,6 +5339,7 @@ class PowerFeedTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class VirtualDeviceContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class VirtualDeviceContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = VirtualDeviceContext.objects.all()
|
queryset = VirtualDeviceContext.objects.all()
|
||||||
filterset = VirtualDeviceContextFilterSet
|
filterset = VirtualDeviceContextFilterSet
|
||||||
|
ignore_fields = ('primary_ip4', 'primary_ip6')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -5401,15 +5409,22 @@ class VirtualDeviceContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
VirtualDeviceContext.objects.bulk_create(vdcs)
|
VirtualDeviceContext.objects.bulk_create(vdcs)
|
||||||
|
|
||||||
interfaces = (
|
interfaces = (
|
||||||
Interface(device=devices[0], name='Interface 1', type='virtual'),
|
Interface(device=devices[0], name='Interface 1', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
Interface(device=devices[0], name='Interface 2', type='virtual'),
|
Interface(device=devices[0], name='Interface 2', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=devices[1], name='Interface 3', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=devices[1], name='Interface 4', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=devices[2], name='Interface 5', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
|
Interface(device=devices[2], name='Interface 6', type=InterfaceTypeChoices.TYPE_VIRTUAL),
|
||||||
)
|
)
|
||||||
Interface.objects.bulk_create(interfaces)
|
Interface.objects.bulk_create(interfaces)
|
||||||
|
|
||||||
interfaces[0].vdcs.set([vdcs[0]])
|
interfaces[0].vdcs.set([vdcs[0]])
|
||||||
interfaces[1].vdcs.set([vdcs[1]])
|
interfaces[1].vdcs.set([vdcs[1]])
|
||||||
|
interfaces[2].vdcs.set([vdcs[2]])
|
||||||
|
interfaces[3].vdcs.set([vdcs[3]])
|
||||||
|
interfaces[4].vdcs.set([vdcs[4]])
|
||||||
|
interfaces[5].vdcs.set([vdcs[5]])
|
||||||
|
|
||||||
addresses = (
|
ip_addresses = (
|
||||||
IPAddress(assigned_object=interfaces[0], address='10.1.1.1/24'),
|
IPAddress(assigned_object=interfaces[0], address='10.1.1.1/24'),
|
||||||
IPAddress(assigned_object=interfaces[1], address='10.1.1.2/24'),
|
IPAddress(assigned_object=interfaces[1], address='10.1.1.2/24'),
|
||||||
IPAddress(assigned_object=None, address='10.1.1.3/24'),
|
IPAddress(assigned_object=None, address='10.1.1.3/24'),
|
||||||
@ -5417,13 +5432,12 @@ class VirtualDeviceContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
IPAddress(assigned_object=interfaces[1], address='2001:db8::2/64'),
|
IPAddress(assigned_object=interfaces[1], address='2001:db8::2/64'),
|
||||||
IPAddress(assigned_object=None, address='2001:db8::3/64'),
|
IPAddress(assigned_object=None, address='2001:db8::3/64'),
|
||||||
)
|
)
|
||||||
IPAddress.objects.bulk_create(addresses)
|
IPAddress.objects.bulk_create(ip_addresses)
|
||||||
|
vdcs[0].primary_ip4 = ip_addresses[0]
|
||||||
vdcs[0].primary_ip4 = addresses[0]
|
vdcs[0].primary_ip6 = ip_addresses[3]
|
||||||
vdcs[0].primary_ip6 = addresses[3]
|
|
||||||
vdcs[0].save()
|
vdcs[0].save()
|
||||||
vdcs[1].primary_ip4 = addresses[1]
|
vdcs[1].primary_ip4 = ip_addresses[1]
|
||||||
vdcs[1].primary_ip6 = addresses[4]
|
vdcs[1].primary_ip6 = ip_addresses[4]
|
||||||
vdcs[1].save()
|
vdcs[1].save()
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
@ -5431,8 +5445,11 @@ class VirtualDeviceContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
def test_device(self):
|
def test_device(self):
|
||||||
params = {'device': ['Device 1', 'Device 2']}
|
devices = Device.objects.filter(name__in=['Device 1', 'Device 2'])
|
||||||
|
params = {'device': [devices[0].name, devices[1].name]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
|
||||||
|
params = {'device_id': [devices[0].pk, devices[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
|
||||||
def test_status(self):
|
def test_status(self):
|
||||||
params = {'status': ['active']}
|
params = {'status': ['active']}
|
||||||
@ -5442,10 +5459,10 @@ class VirtualDeviceContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'description': ['foobar1', 'foobar2']}
|
params = {'description': ['foobar1', 'foobar2']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_device_id(self):
|
def test_interface(self):
|
||||||
devices = Device.objects.filter(name__in=['Device 1', 'Device 2'])
|
interfaces = Interface.objects.filter(name__in=['Interface 1', 'Interface 3'])
|
||||||
params = {'device_id': [devices[0].pk, devices[1].pk]}
|
params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_has_primary_ip(self):
|
def test_has_primary_ip(self):
|
||||||
params = {'has_primary_ip': True}
|
params = {'has_primary_ip': True}
|
||||||
|
@ -40,12 +40,14 @@ class ScriptFilterSet(BaseFilterSet):
|
|||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
|
module_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=ScriptModule.objects.all(),
|
||||||
|
label=_('Script module (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Script
|
model = Script
|
||||||
fields = [
|
fields = ('id', 'name', 'is_executable')
|
||||||
'id', 'name',
|
|
||||||
]
|
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -69,10 +71,10 @@ class WebhookFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Webhook
|
model = Webhook
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'name', 'payload_url', 'http_method', 'http_content_type', 'secret', 'ssl_verification',
|
'id', 'name', 'payload_url', 'http_method', 'http_content_type', 'secret', 'ssl_verification',
|
||||||
'ca_file_path', 'description',
|
'ca_file_path', 'description',
|
||||||
]
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -89,8 +91,9 @@ class EventRuleFilterSet(NetBoxModelFilterSet):
|
|||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
object_type_id = MultiValueNumberFilter(
|
object_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='object_types__id'
|
queryset=ObjectType.objects.all(),
|
||||||
|
field_name='object_types'
|
||||||
)
|
)
|
||||||
object_type = ContentTypeFilter(
|
object_type = ContentTypeFilter(
|
||||||
field_name='object_types'
|
field_name='object_types'
|
||||||
@ -103,10 +106,10 @@ class EventRuleFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = EventRule
|
model = EventRule
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'name', 'type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end', 'enabled',
|
'id', 'name', 'type_create', 'type_update', 'type_delete', 'type_job_start', 'type_job_end', 'enabled',
|
||||||
'action_type', 'description',
|
'action_type', 'description',
|
||||||
]
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -118,7 +121,7 @@ class EventRuleFilterSet(NetBoxModelFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldFilterSet(BaseFilterSet):
|
class CustomFieldFilterSet(ChangeLoggedModelFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
@ -126,14 +129,16 @@ class CustomFieldFilterSet(BaseFilterSet):
|
|||||||
type = django_filters.MultipleChoiceFilter(
|
type = django_filters.MultipleChoiceFilter(
|
||||||
choices=CustomFieldTypeChoices
|
choices=CustomFieldTypeChoices
|
||||||
)
|
)
|
||||||
object_type_id = MultiValueNumberFilter(
|
object_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='object_types__id'
|
queryset=ObjectType.objects.all(),
|
||||||
|
field_name='object_types'
|
||||||
)
|
)
|
||||||
object_type = ContentTypeFilter(
|
object_type = ContentTypeFilter(
|
||||||
field_name='object_types'
|
field_name='object_types'
|
||||||
)
|
)
|
||||||
related_object_type_id = MultiValueNumberFilter(
|
related_object_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='related_object_type__id'
|
queryset=ObjectType.objects.all(),
|
||||||
|
field_name='related_object_type'
|
||||||
)
|
)
|
||||||
related_object_type = ContentTypeFilter()
|
related_object_type = ContentTypeFilter()
|
||||||
choice_set_id = django_filters.ModelMultipleChoiceFilter(
|
choice_set_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
@ -147,10 +152,11 @@ class CustomFieldFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CustomField
|
model = CustomField
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'name', 'group_name', 'required', 'search_weight', 'filter_logic', 'ui_visible', 'ui_editable',
|
'id', 'name', 'label', 'group_name', 'required', 'search_weight', 'filter_logic', 'ui_visible',
|
||||||
'weight', 'is_cloneable', 'description',
|
'ui_editable', 'weight', 'is_cloneable', 'description', 'validation_minimum', 'validation_maximum',
|
||||||
]
|
'validation_regex',
|
||||||
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -163,7 +169,7 @@ class CustomFieldFilterSet(BaseFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldChoiceSetFilterSet(BaseFilterSet):
|
class CustomFieldChoiceSetFilterSet(ChangeLoggedModelFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
@ -174,9 +180,9 @@ class CustomFieldChoiceSetFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CustomFieldChoiceSet
|
model = CustomFieldChoiceSet
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'name', 'description', 'base_choices', 'order_alphabetically',
|
'id', 'name', 'description', 'base_choices', 'order_alphabetically',
|
||||||
]
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -191,13 +197,14 @@ class CustomFieldChoiceSetFilterSet(BaseFilterSet):
|
|||||||
return queryset.filter(extra_choices__overlap=value)
|
return queryset.filter(extra_choices__overlap=value)
|
||||||
|
|
||||||
|
|
||||||
class CustomLinkFilterSet(BaseFilterSet):
|
class CustomLinkFilterSet(ChangeLoggedModelFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
object_type_id = MultiValueNumberFilter(
|
object_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='object_types__id'
|
queryset=ObjectType.objects.all(),
|
||||||
|
field_name='object_types'
|
||||||
)
|
)
|
||||||
object_type = ContentTypeFilter(
|
object_type = ContentTypeFilter(
|
||||||
field_name='object_types'
|
field_name='object_types'
|
||||||
@ -205,9 +212,9 @@ class CustomLinkFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = CustomLink
|
model = CustomLink
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'name', 'enabled', 'link_text', 'link_url', 'weight', 'group_name', 'new_window',
|
'id', 'name', 'enabled', 'link_text', 'link_url', 'weight', 'group_name', 'new_window', 'button_class',
|
||||||
]
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -220,13 +227,14 @@ class CustomLinkFilterSet(BaseFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ExportTemplateFilterSet(BaseFilterSet):
|
class ExportTemplateFilterSet(ChangeLoggedModelFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
object_type_id = MultiValueNumberFilter(
|
object_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='object_types__id'
|
queryset=ObjectType.objects.all(),
|
||||||
|
field_name='object_types'
|
||||||
)
|
)
|
||||||
object_type = ContentTypeFilter(
|
object_type = ContentTypeFilter(
|
||||||
field_name='object_types'
|
field_name='object_types'
|
||||||
@ -242,7 +250,10 @@ class ExportTemplateFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ExportTemplate
|
model = ExportTemplate
|
||||||
fields = ['id', 'name', 'description', 'data_synced']
|
fields = (
|
||||||
|
'id', 'name', 'description', 'mime_type', 'file_extension', 'as_attachment', 'auto_sync_enabled',
|
||||||
|
'data_synced',
|
||||||
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -253,13 +264,14 @@ class ExportTemplateFilterSet(BaseFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class SavedFilterFilterSet(BaseFilterSet):
|
class SavedFilterFilterSet(ChangeLoggedModelFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
object_type_id = MultiValueNumberFilter(
|
object_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='object_types__id'
|
queryset=ObjectType.objects.all(),
|
||||||
|
field_name='object_types'
|
||||||
)
|
)
|
||||||
object_type = ContentTypeFilter(
|
object_type = ContentTypeFilter(
|
||||||
field_name='object_types'
|
field_name='object_types'
|
||||||
@ -280,7 +292,7 @@ class SavedFilterFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SavedFilter
|
model = SavedFilter
|
||||||
fields = ['id', 'name', 'slug', 'description', 'enabled', 'shared', 'weight']
|
fields = ('id', 'name', 'slug', 'description', 'enabled', 'shared', 'weight')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -321,20 +333,19 @@ class BookmarkFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Bookmark
|
model = Bookmark
|
||||||
fields = ['id', 'object_id']
|
fields = ('id', 'object_id')
|
||||||
|
|
||||||
|
|
||||||
class ImageAttachmentFilterSet(BaseFilterSet):
|
class ImageAttachmentFilterSet(ChangeLoggedModelFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
created = django_filters.DateTimeFilter()
|
|
||||||
object_type = ContentTypeFilter()
|
object_type = ContentTypeFilter()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ImageAttachment
|
model = ImageAttachment
|
||||||
fields = ['id', 'object_type_id', 'object_id', 'name']
|
fields = ('id', 'object_type_id', 'object_id', 'name', 'image_width', 'image_height')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -364,7 +375,7 @@ class JournalEntryFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = JournalEntry
|
model = JournalEntry
|
||||||
fields = ['id', 'assigned_object_type_id', 'assigned_object_id', 'created', 'kind']
|
fields = ('id', 'assigned_object_type_id', 'assigned_object_id', 'created', 'kind')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -389,7 +400,7 @@ class TagFilterSet(ChangeLoggedModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Tag
|
model = Tag
|
||||||
fields = ['id', 'name', 'slug', 'color', 'description', 'object_types']
|
fields = ('id', 'name', 'slug', 'color', 'description', 'object_types')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -486,12 +497,12 @@ class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
|
|||||||
queryset=DeviceType.objects.all(),
|
queryset=DeviceType.objects.all(),
|
||||||
label=_('Device type'),
|
label=_('Device type'),
|
||||||
)
|
)
|
||||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
device_role_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='roles',
|
field_name='roles',
|
||||||
queryset=DeviceRole.objects.all(),
|
queryset=DeviceRole.objects.all(),
|
||||||
label=_('Role'),
|
label=_('Role'),
|
||||||
)
|
)
|
||||||
role = django_filters.ModelMultipleChoiceFilter(
|
device_role = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='roles__slug',
|
field_name='roles__slug',
|
||||||
queryset=DeviceRole.objects.all(),
|
queryset=DeviceRole.objects.all(),
|
||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
@ -577,9 +588,13 @@ class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
|
|||||||
label=_('Data file (ID)'),
|
label=_('Data file (ID)'),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Remove in v4.1
|
||||||
|
role = device_role
|
||||||
|
role_id = device_role_id
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConfigContext
|
model = ConfigContext
|
||||||
fields = ['id', 'name', 'is_active', 'data_synced', 'description']
|
fields = ('id', 'name', 'is_active', 'description', 'weight', 'auto_sync_enabled', 'data_synced')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -591,7 +606,7 @@ class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ConfigTemplateFilterSet(BaseFilterSet):
|
class ConfigTemplateFilterSet(ChangeLoggedModelFilterSet):
|
||||||
q = django_filters.CharFilter(
|
q = django_filters.CharFilter(
|
||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
@ -608,7 +623,7 @@ class ConfigTemplateFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ConfigTemplate
|
model = ConfigTemplate
|
||||||
fields = ['id', 'name', 'description', 'data_synced']
|
fields = ('id', 'name', 'description', 'auto_sync_enabled', 'data_synced')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -656,10 +671,10 @@ class ObjectChangeFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ObjectChange
|
model = ObjectChange
|
||||||
fields = [
|
fields = (
|
||||||
'id', 'user', 'user_name', 'request_id', 'action', 'changed_object_type_id', 'changed_object_id',
|
'id', 'user', 'user_name', 'request_id', 'action', 'changed_object_type_id', 'changed_object_id',
|
||||||
'object_repr',
|
'related_object_type', 'related_object_id', 'object_repr',
|
||||||
]
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -682,7 +697,7 @@ class ObjectTypeFilterSet(django_filters.FilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ObjectType
|
model = ObjectType
|
||||||
fields = ['id', 'app_label', 'model']
|
fields = ('id', 'app_label', 'model')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -23,9 +23,10 @@ from virtualization.models import Cluster, ClusterGroup, ClusterType
|
|||||||
User = get_user_model()
|
User = get_user_model()
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldTestCase(TestCase, BaseFilterSetTests):
|
class CustomFieldTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = CustomField.objects.all()
|
queryset = CustomField.objects.all()
|
||||||
filterset = CustomFieldFilterSet
|
filterset = CustomFieldFilterSet
|
||||||
|
ignore_fields = ('default',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -155,9 +156,10 @@ class CustomFieldTestCase(TestCase, BaseFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldChoiceSetTestCase(TestCase, BaseFilterSetTests):
|
class CustomFieldChoiceSetTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = CustomFieldChoiceSet.objects.all()
|
queryset = CustomFieldChoiceSet.objects.all()
|
||||||
filterset = CustomFieldChoiceSetFilterSet
|
filterset = CustomFieldChoiceSetFilterSet
|
||||||
|
ignore_fields = ('extra_choices',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -188,6 +190,7 @@ class CustomFieldChoiceSetTestCase(TestCase, BaseFilterSetTests):
|
|||||||
class WebhookTestCase(TestCase, BaseFilterSetTests):
|
class WebhookTestCase(TestCase, BaseFilterSetTests):
|
||||||
queryset = Webhook.objects.all()
|
queryset = Webhook.objects.all()
|
||||||
filterset = WebhookFilterSet
|
filterset = WebhookFilterSet
|
||||||
|
ignore_fields = ('additional_headers', 'body_template')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -252,6 +255,7 @@ class WebhookTestCase(TestCase, BaseFilterSetTests):
|
|||||||
class EventRuleTestCase(TestCase, BaseFilterSetTests):
|
class EventRuleTestCase(TestCase, BaseFilterSetTests):
|
||||||
queryset = EventRule.objects.all()
|
queryset = EventRule.objects.all()
|
||||||
filterset = EventRuleFilterSet
|
filterset = EventRuleFilterSet
|
||||||
|
ignore_fields = ('action_data', 'conditions')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -405,7 +409,7 @@ class EventRuleTestCase(TestCase, BaseFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
|
|
||||||
class CustomLinkTestCase(TestCase, BaseFilterSetTests):
|
class CustomLinkTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = CustomLink.objects.all()
|
queryset = CustomLink.objects.all()
|
||||||
filterset = CustomLinkFilterSet
|
filterset = CustomLinkFilterSet
|
||||||
|
|
||||||
@ -474,9 +478,10 @@ class CustomLinkTestCase(TestCase, BaseFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
|
|
||||||
class SavedFilterTestCase(TestCase, BaseFilterSetTests):
|
class SavedFilterTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = SavedFilter.objects.all()
|
queryset = SavedFilter.objects.all()
|
||||||
filterset = SavedFilterFilterSet
|
filterset = SavedFilterFilterSet
|
||||||
|
ignore_fields = ('parameters',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -647,9 +652,10 @@ class BookmarkTestCase(TestCase, BaseFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
|
||||||
|
|
||||||
class ExportTemplateTestCase(TestCase, BaseFilterSetTests):
|
class ExportTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = ExportTemplate.objects.all()
|
queryset = ExportTemplate.objects.all()
|
||||||
filterset = ExportTemplateFilterSet
|
filterset = ExportTemplateFilterSet
|
||||||
|
ignore_fields = ('template_code', 'data_path')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -683,9 +689,10 @@ class ExportTemplateTestCase(TestCase, BaseFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class ImageAttachmentTestCase(TestCase, BaseFilterSetTests):
|
class ImageAttachmentTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = ImageAttachment.objects.all()
|
queryset = ImageAttachment.objects.all()
|
||||||
filterset = ImageAttachmentFilterSet
|
filterset = ImageAttachmentFilterSet
|
||||||
|
ignore_fields = ('image',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -760,12 +767,6 @@ class ImageAttachmentTestCase(TestCase, BaseFilterSetTests):
|
|||||||
}
|
}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
|
|
||||||
def test_created(self):
|
|
||||||
pk_list = self.queryset.values_list('pk', flat=True)[:2]
|
|
||||||
self.queryset.filter(pk__in=pk_list).update(created=datetime(2021, 1, 1, 0, 0, 0, tzinfo=timezone.utc))
|
|
||||||
params = {'created': '2021-01-01T00:00:00'}
|
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
||||||
|
|
||||||
|
|
||||||
class JournalEntryTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class JournalEntryTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = JournalEntry.objects.all()
|
queryset = JournalEntry.objects.all()
|
||||||
@ -873,6 +874,7 @@ class JournalEntryTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class ConfigContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class ConfigContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = ConfigContext.objects.all()
|
queryset = ConfigContext.objects.all()
|
||||||
filterset = ConfigContextFilterSet
|
filterset = ConfigContextFilterSet
|
||||||
|
ignore_fields = ('data', 'data_path')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1041,11 +1043,11 @@ class ConfigContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'device_type_id': [device_types[0].pk, device_types[1].pk]}
|
params = {'device_type_id': [device_types[0].pk, device_types[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_role(self):
|
def test_device_role(self):
|
||||||
device_roles = DeviceRole.objects.all()[:2]
|
device_roles = DeviceRole.objects.all()[:2]
|
||||||
params = {'role_id': [device_roles[0].pk, device_roles[1].pk]}
|
params = {'device_role_id': [device_roles[0].pk, device_roles[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
params = {'role': [device_roles[0].slug, device_roles[1].slug]}
|
params = {'device_role': [device_roles[0].slug, device_roles[1].slug]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_platform(self):
|
def test_platform(self):
|
||||||
@ -1096,9 +1098,10 @@ class ConfigContextTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class ConfigTemplateTestCase(TestCase, BaseFilterSetTests):
|
class ConfigTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = ConfigTemplate.objects.all()
|
queryset = ConfigTemplate.objects.all()
|
||||||
filterset = ConfigTemplateFilterSet
|
filterset = ConfigTemplateFilterSet
|
||||||
|
ignore_fields = ('template_code', 'environment_params', 'data_path')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1125,6 +1128,93 @@ class ConfigTemplateTestCase(TestCase, BaseFilterSetTests):
|
|||||||
class TagTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class TagTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = Tag.objects.all()
|
queryset = Tag.objects.all()
|
||||||
filterset = TagFilterSet
|
filterset = TagFilterSet
|
||||||
|
ignore_fields = (
|
||||||
|
'object_types',
|
||||||
|
|
||||||
|
# Reverse relationships (to tagged models) we can ignore
|
||||||
|
'aggregate',
|
||||||
|
'asn',
|
||||||
|
'asnrange',
|
||||||
|
'cable',
|
||||||
|
'circuit',
|
||||||
|
'circuittermination',
|
||||||
|
'circuittype',
|
||||||
|
'cluster',
|
||||||
|
'clustergroup',
|
||||||
|
'clustertype',
|
||||||
|
'configtemplate',
|
||||||
|
'consoleport',
|
||||||
|
'consoleserverport',
|
||||||
|
'contact',
|
||||||
|
'contactassignment',
|
||||||
|
'contactgroup',
|
||||||
|
'contactrole',
|
||||||
|
'datasource',
|
||||||
|
'device',
|
||||||
|
'devicebay',
|
||||||
|
'devicerole',
|
||||||
|
'devicetype',
|
||||||
|
'dummymodel', # From dummy_plugin
|
||||||
|
'eventrule',
|
||||||
|
'fhrpgroup',
|
||||||
|
'frontport',
|
||||||
|
'ikepolicy',
|
||||||
|
'ikeproposal',
|
||||||
|
'interface',
|
||||||
|
'inventoryitem',
|
||||||
|
'inventoryitemrole',
|
||||||
|
'ipaddress',
|
||||||
|
'iprange',
|
||||||
|
'ipsecpolicy',
|
||||||
|
'ipsecprofile',
|
||||||
|
'ipsecproposal',
|
||||||
|
'journalentry',
|
||||||
|
'l2vpn',
|
||||||
|
'l2vpntermination',
|
||||||
|
'location',
|
||||||
|
'manufacturer',
|
||||||
|
'module',
|
||||||
|
'modulebay',
|
||||||
|
'moduletype',
|
||||||
|
'platform',
|
||||||
|
'powerfeed',
|
||||||
|
'poweroutlet',
|
||||||
|
'powerpanel',
|
||||||
|
'powerport',
|
||||||
|
'prefix',
|
||||||
|
'provider',
|
||||||
|
'provideraccount',
|
||||||
|
'providernetwork',
|
||||||
|
'rack',
|
||||||
|
'rackreservation',
|
||||||
|
'rackrole',
|
||||||
|
'rearport',
|
||||||
|
'region',
|
||||||
|
'rir',
|
||||||
|
'role',
|
||||||
|
'routetarget',
|
||||||
|
'service',
|
||||||
|
'servicetemplate',
|
||||||
|
'site',
|
||||||
|
'sitegroup',
|
||||||
|
'tenant',
|
||||||
|
'tenantgroup',
|
||||||
|
'tunnel',
|
||||||
|
'tunnelgroup',
|
||||||
|
'tunneltermination',
|
||||||
|
'virtualchassis',
|
||||||
|
'virtualdevicecontext',
|
||||||
|
'virtualdisk',
|
||||||
|
'virtualmachine',
|
||||||
|
'vlan',
|
||||||
|
'vlangroup',
|
||||||
|
'vminterface',
|
||||||
|
'vrf',
|
||||||
|
'webhook',
|
||||||
|
'wirelesslan',
|
||||||
|
'wirelesslangroup',
|
||||||
|
'wirelesslink',
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1193,6 +1283,7 @@ class TagTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class ObjectChangeTestCase(TestCase, BaseFilterSetTests):
|
class ObjectChangeTestCase(TestCase, BaseFilterSetTests):
|
||||||
queryset = ObjectChange.objects.all()
|
queryset = ObjectChange.objects.all()
|
||||||
filterset = ObjectChangeFilterSet
|
filterset = ObjectChangeFilterSet
|
||||||
|
ignore_fields = ('prechange_data', 'postchange_data')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -8,6 +8,7 @@ from drf_spectacular.types import OpenApiTypes
|
|||||||
from drf_spectacular.utils import extend_schema_field
|
from drf_spectacular.utils import extend_schema_field
|
||||||
from netaddr.core import AddrFormatError
|
from netaddr.core import AddrFormatError
|
||||||
|
|
||||||
|
from circuits.models import Provider
|
||||||
from dcim.models import Device, Interface, Region, Site, SiteGroup
|
from dcim.models import Device, Interface, Region, Site, SiteGroup
|
||||||
from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet
|
from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet
|
||||||
from tenancy.filtersets import TenancyFilterSet
|
from tenancy.filtersets import TenancyFilterSet
|
||||||
@ -75,7 +76,7 @@ class VRFFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VRF
|
model = VRF
|
||||||
fields = ['id', 'name', 'rd', 'enforce_unique', 'description']
|
fields = ('id', 'name', 'rd', 'enforce_unique', 'description')
|
||||||
|
|
||||||
|
|
||||||
class RouteTargetFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
class RouteTargetFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||||
@ -101,6 +102,28 @@ class RouteTargetFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
to_field_name='rd',
|
to_field_name='rd',
|
||||||
label=_('Export VRF (RD)'),
|
label=_('Export VRF (RD)'),
|
||||||
)
|
)
|
||||||
|
importing_l2vpn_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='importing_l2vpns',
|
||||||
|
queryset=L2VPN.objects.all(),
|
||||||
|
label=_('Importing L2VPN'),
|
||||||
|
)
|
||||||
|
importing_l2vpn = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='importing_l2vpns__identifier',
|
||||||
|
queryset=L2VPN.objects.all(),
|
||||||
|
to_field_name='identifier',
|
||||||
|
label=_('Importing L2VPN (identifier)'),
|
||||||
|
)
|
||||||
|
exporting_l2vpn_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='exporting_l2vpns',
|
||||||
|
queryset=L2VPN.objects.all(),
|
||||||
|
label=_('Exporting L2VPN'),
|
||||||
|
)
|
||||||
|
exporting_l2vpn = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='exporting_l2vpns__identifier',
|
||||||
|
queryset=L2VPN.objects.all(),
|
||||||
|
to_field_name='identifier',
|
||||||
|
label=_('Exporting L2VPN (identifier)'),
|
||||||
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -112,14 +135,14 @@ class RouteTargetFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RouteTarget
|
model = RouteTarget
|
||||||
fields = ['id', 'name', 'description']
|
fields = ('id', 'name', 'description')
|
||||||
|
|
||||||
|
|
||||||
class RIRFilterSet(OrganizationalModelFilterSet):
|
class RIRFilterSet(OrganizationalModelFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = RIR
|
model = RIR
|
||||||
fields = ['id', 'name', 'slug', 'is_private', 'description']
|
fields = ('id', 'name', 'slug', 'is_private', 'description')
|
||||||
|
|
||||||
|
|
||||||
class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||||
@ -144,7 +167,7 @@ class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Aggregate
|
model = Aggregate
|
||||||
fields = ['id', 'date_added', 'description']
|
fields = ('id', 'date_added', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -183,7 +206,7 @@ class ASNRangeFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ASNRange
|
model = ASNRange
|
||||||
fields = ['id', 'name', 'start', 'end', 'description']
|
fields = ('id', 'name', 'slug', 'start', 'end', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -214,10 +237,21 @@ class ASNFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
|
|||||||
to_field_name='slug',
|
to_field_name='slug',
|
||||||
label=_('Site (slug)'),
|
label=_('Site (slug)'),
|
||||||
)
|
)
|
||||||
|
provider_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='providers',
|
||||||
|
queryset=Provider.objects.all(),
|
||||||
|
label=_('Provider (ID)'),
|
||||||
|
)
|
||||||
|
provider = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='providers__slug',
|
||||||
|
queryset=Provider.objects.all(),
|
||||||
|
to_field_name='slug',
|
||||||
|
label=_('Provider (slug)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ASN
|
model = ASN
|
||||||
fields = ['id', 'asn', 'description']
|
fields = ('id', 'asn', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -234,7 +268,7 @@ class RoleFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Role
|
model = Role
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description', 'weight')
|
||||||
|
|
||||||
|
|
||||||
class PrefixFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
class PrefixFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||||
@ -359,7 +393,7 @@ class PrefixFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Prefix
|
model = Prefix
|
||||||
fields = ['id', 'is_pool', 'mark_utilized', 'description']
|
fields = ('id', 'is_pool', 'mark_utilized', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -475,7 +509,7 @@ class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPRange
|
model = IPRange
|
||||||
fields = ['id', 'mark_utilized', 'description']
|
fields = ('id', 'mark_utilized', 'size', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -628,10 +662,20 @@ class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
role = django_filters.MultipleChoiceFilter(
|
role = django_filters.MultipleChoiceFilter(
|
||||||
choices=IPAddressRoleChoices
|
choices=IPAddressRoleChoices
|
||||||
)
|
)
|
||||||
|
service_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='services',
|
||||||
|
queryset=Service.objects.all(),
|
||||||
|
label=_('Service (ID)'),
|
||||||
|
)
|
||||||
|
nat_inside_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='nat_inside',
|
||||||
|
queryset=IPAddress.objects.all(),
|
||||||
|
label=_('NAT inside IP address (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPAddress
|
model = IPAddress
|
||||||
fields = ['id', 'dns_name', 'description']
|
fields = ('id', 'dns_name', 'description', 'assigned_object_type', 'assigned_object_id')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -758,7 +802,7 @@ class FHRPGroupFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FHRPGroup
|
model = FHRPGroup
|
||||||
fields = ['id', 'group_id', 'name', 'auth_key', 'description']
|
fields = ('id', 'group_id', 'name', 'auth_key', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -819,7 +863,7 @@ class FHRPGroupAssignmentFilterSet(ChangeLoggedModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = FHRPGroupAssignment
|
model = FHRPGroupAssignment
|
||||||
fields = ['id', 'group_id', 'interface_type', 'interface_id', 'priority']
|
fields = ('id', 'group_id', 'interface_type', 'interface_id', 'priority')
|
||||||
|
|
||||||
def filter_device(self, queryset, name, value):
|
def filter_device(self, queryset, name, value):
|
||||||
devices = Device.objects.filter(**{f'{name}__in': value})
|
devices = Device.objects.filter(**{f'{name}__in': value})
|
||||||
@ -849,7 +893,7 @@ class VLANGroupFilterSet(OrganizationalModelFilterSet):
|
|||||||
region = django_filters.NumberFilter(
|
region = django_filters.NumberFilter(
|
||||||
method='filter_scope'
|
method='filter_scope'
|
||||||
)
|
)
|
||||||
sitegroup = django_filters.NumberFilter(
|
site_group = django_filters.NumberFilter(
|
||||||
method='filter_scope'
|
method='filter_scope'
|
||||||
)
|
)
|
||||||
site = django_filters.NumberFilter(
|
site = django_filters.NumberFilter(
|
||||||
@ -861,16 +905,20 @@ class VLANGroupFilterSet(OrganizationalModelFilterSet):
|
|||||||
rack = django_filters.NumberFilter(
|
rack = django_filters.NumberFilter(
|
||||||
method='filter_scope'
|
method='filter_scope'
|
||||||
)
|
)
|
||||||
clustergroup = django_filters.NumberFilter(
|
cluster_group = django_filters.NumberFilter(
|
||||||
method='filter_scope'
|
method='filter_scope'
|
||||||
)
|
)
|
||||||
cluster = django_filters.NumberFilter(
|
cluster = django_filters.NumberFilter(
|
||||||
method='filter_scope'
|
method='filter_scope'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Remove in v4.1
|
||||||
|
sitegroup = site_group
|
||||||
|
clustergroup = cluster_group
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VLANGroup
|
model = VLANGroup
|
||||||
fields = ['id', 'name', 'slug', 'min_vid', 'max_vid', 'description', 'scope_id']
|
fields = ('id', 'name', 'slug', 'min_vid', 'max_vid', 'description', 'scope_id')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -882,8 +930,9 @@ class VLANGroupFilterSet(OrganizationalModelFilterSet):
|
|||||||
return queryset.filter(qs_filter)
|
return queryset.filter(qs_filter)
|
||||||
|
|
||||||
def filter_scope(self, queryset, name, value):
|
def filter_scope(self, queryset, name, value):
|
||||||
|
model_name = name.replace('_', '')
|
||||||
return queryset.filter(
|
return queryset.filter(
|
||||||
scope_type=ContentType.objects.get(model=name),
|
scope_type=ContentType.objects.get(model=model_name),
|
||||||
scope_id=value
|
scope_id=value
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -975,7 +1024,7 @@ class VLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VLAN
|
model = VLAN
|
||||||
fields = ['id', 'vid', 'name', 'description']
|
fields = ('id', 'vid', 'name', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -1008,7 +1057,7 @@ class ServiceTemplateFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ServiceTemplate
|
model = ServiceTemplate
|
||||||
fields = ['id', 'name', 'protocol', 'description']
|
fields = ('id', 'name', 'protocol', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -1041,26 +1090,29 @@ class ServiceFilterSet(NetBoxModelFilterSet):
|
|||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
label=_('Virtual machine (name)'),
|
label=_('Virtual machine (name)'),
|
||||||
)
|
)
|
||||||
ipaddress_id = django_filters.ModelMultipleChoiceFilter(
|
ip_address_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='ipaddresses',
|
field_name='ipaddresses',
|
||||||
queryset=IPAddress.objects.all(),
|
queryset=IPAddress.objects.all(),
|
||||||
label=_('IP address (ID)'),
|
label=_('IP address (ID)'),
|
||||||
)
|
)
|
||||||
ipaddress = django_filters.ModelMultipleChoiceFilter(
|
ip_address = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='ipaddresses__address',
|
field_name='ipaddresses__address',
|
||||||
queryset=IPAddress.objects.all(),
|
queryset=IPAddress.objects.all(),
|
||||||
to_field_name='address',
|
to_field_name='address',
|
||||||
label=_('IP address'),
|
label=_('IP address'),
|
||||||
)
|
)
|
||||||
|
|
||||||
port = NumericArrayFilter(
|
port = NumericArrayFilter(
|
||||||
field_name='ports',
|
field_name='ports',
|
||||||
lookup_expr='contains'
|
lookup_expr='contains'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Remove in v4.1
|
||||||
|
ipaddress = ip_address
|
||||||
|
ipaddress_id = ip_address_id
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Service
|
model = Service
|
||||||
fields = ['id', 'name', 'protocol', 'description']
|
fields = ('id', 'name', 'protocol', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -304,7 +304,7 @@ class IPAddressFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
|
|||||||
'placeholder': 'Prefix',
|
'placeholder': 'Prefix',
|
||||||
}
|
}
|
||||||
),
|
),
|
||||||
label='Parent Prefix'
|
label=_('Parent Prefix')
|
||||||
)
|
)
|
||||||
family = forms.ChoiceField(
|
family = forms.ChoiceField(
|
||||||
required=False,
|
required=False,
|
||||||
|
@ -2,6 +2,7 @@ from django.contrib.contenttypes.models import ContentType
|
|||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from netaddr import IPNetwork
|
from netaddr import IPNetwork
|
||||||
|
|
||||||
|
from circuits.models import Provider
|
||||||
from dcim.choices import InterfaceTypeChoices
|
from dcim.choices import InterfaceTypeChoices
|
||||||
from dcim.models import Device, DeviceRole, DeviceType, Interface, Location, Manufacturer, Rack, Region, Site, SiteGroup
|
from dcim.models import Device, DeviceRole, DeviceType, Interface, Location, Manufacturer, Rack, Region, Site, SiteGroup
|
||||||
from ipam.choices import *
|
from ipam.choices import *
|
||||||
@ -10,6 +11,8 @@ from ipam.models import *
|
|||||||
from tenancy.models import Tenant, TenantGroup
|
from tenancy.models import Tenant, TenantGroup
|
||||||
from utilities.testing import ChangeLoggedFilterSetTests, create_test_device, create_test_virtualmachine
|
from utilities.testing import ChangeLoggedFilterSetTests, create_test_device, create_test_virtualmachine
|
||||||
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
|
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
|
||||||
|
from vpn.choices import L2VPNTypeChoices
|
||||||
|
from vpn.models import L2VPN
|
||||||
|
|
||||||
|
|
||||||
class ASNRangeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class ASNRangeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
@ -110,13 +113,6 @@ class ASNTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
]
|
]
|
||||||
RIR.objects.bulk_create(rirs)
|
RIR.objects.bulk_create(rirs)
|
||||||
|
|
||||||
sites = [
|
|
||||||
Site(name='Site 1', slug='site-1'),
|
|
||||||
Site(name='Site 2', slug='site-2'),
|
|
||||||
Site(name='Site 3', slug='site-3')
|
|
||||||
]
|
|
||||||
Site.objects.bulk_create(sites)
|
|
||||||
|
|
||||||
tenants = [
|
tenants = [
|
||||||
Tenant(name='Tenant 1', slug='tenant-1'),
|
Tenant(name='Tenant 1', slug='tenant-1'),
|
||||||
Tenant(name='Tenant 2', slug='tenant-2'),
|
Tenant(name='Tenant 2', slug='tenant-2'),
|
||||||
@ -136,6 +132,12 @@ class ASNTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
)
|
)
|
||||||
ASN.objects.bulk_create(asns)
|
ASN.objects.bulk_create(asns)
|
||||||
|
|
||||||
|
sites = [
|
||||||
|
Site(name='Site 1', slug='site-1'),
|
||||||
|
Site(name='Site 2', slug='site-2'),
|
||||||
|
Site(name='Site 3', slug='site-3')
|
||||||
|
]
|
||||||
|
Site.objects.bulk_create(sites)
|
||||||
asns[0].sites.set([sites[0]])
|
asns[0].sites.set([sites[0]])
|
||||||
asns[1].sites.set([sites[1]])
|
asns[1].sites.set([sites[1]])
|
||||||
asns[2].sites.set([sites[2]])
|
asns[2].sites.set([sites[2]])
|
||||||
@ -143,6 +145,16 @@ class ASNTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
asns[4].sites.set([sites[1]])
|
asns[4].sites.set([sites[1]])
|
||||||
asns[5].sites.set([sites[2]])
|
asns[5].sites.set([sites[2]])
|
||||||
|
|
||||||
|
providers = (
|
||||||
|
Provider(name='Provider 1', slug='provider-1'),
|
||||||
|
Provider(name='Provider 2', slug='provider-2'),
|
||||||
|
Provider(name='Provider 3', slug='provider-3'),
|
||||||
|
)
|
||||||
|
Provider.objects.bulk_create(providers)
|
||||||
|
providers[0].asns.add(asns[0])
|
||||||
|
providers[1].asns.add(asns[1])
|
||||||
|
providers[2].asns.add(asns[2])
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
params = {'q': 'foobar1'}
|
params = {'q': 'foobar1'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
@ -176,11 +188,24 @@ class ASNTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'description': ['foobar1', 'foobar2']}
|
params = {'description': ['foobar1', 'foobar2']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_provider(self):
|
||||||
|
providers = Provider.objects.all()[:2]
|
||||||
|
params = {'provider_id': [providers[0].pk, providers[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class VRFTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class VRFTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = VRF.objects.all()
|
queryset = VRF.objects.all()
|
||||||
filterset = VRFFilterSet
|
filterset = VRFFilterSet
|
||||||
|
|
||||||
|
def get_m2m_filter_name(self, field):
|
||||||
|
# Override filter names for import & export RouteTargets
|
||||||
|
if field.name == 'import_targets':
|
||||||
|
return 'import_target'
|
||||||
|
if field.name == 'export_targets':
|
||||||
|
return 'export_target'
|
||||||
|
return ChangeLoggedFilterSetTests.get_m2m_filter_name(field)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
||||||
@ -277,6 +302,18 @@ class RouteTargetTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
queryset = RouteTarget.objects.all()
|
queryset = RouteTarget.objects.all()
|
||||||
filterset = RouteTargetFilterSet
|
filterset = RouteTargetFilterSet
|
||||||
|
|
||||||
|
def get_m2m_filter_name(self, field):
|
||||||
|
# Override filter names for import & export VRFs and L2VPNs
|
||||||
|
if field.name == 'importing_vrfs':
|
||||||
|
return 'importing_vrf'
|
||||||
|
if field.name == 'exporting_vrfs':
|
||||||
|
return 'exporting_vrf'
|
||||||
|
if field.name == 'importing_l2vpns':
|
||||||
|
return 'importing_l2vpn'
|
||||||
|
if field.name == 'exporting_l2vpns':
|
||||||
|
return 'exporting_l2vpn'
|
||||||
|
return ChangeLoggedFilterSetTests.get_m2m_filter_name(field)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
||||||
@ -322,6 +359,17 @@ class RouteTargetTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
vrfs[1].import_targets.add(route_targets[4], route_targets[5])
|
vrfs[1].import_targets.add(route_targets[4], route_targets[5])
|
||||||
vrfs[1].export_targets.add(route_targets[6], route_targets[7])
|
vrfs[1].export_targets.add(route_targets[6], route_targets[7])
|
||||||
|
|
||||||
|
l2vpns = (
|
||||||
|
L2VPN(name='L2VPN 1', slug='l2vpn-1', type=L2VPNTypeChoices.TYPE_VXLAN, identifier=100),
|
||||||
|
L2VPN(name='L2VPN 2', slug='l2vpn-2', type=L2VPNTypeChoices.TYPE_VXLAN, identifier=200),
|
||||||
|
L2VPN(name='L2VPN 3', slug='l2vpn-3', type=L2VPNTypeChoices.TYPE_VXLAN, identifier=300),
|
||||||
|
)
|
||||||
|
L2VPN.objects.bulk_create(l2vpns)
|
||||||
|
l2vpns[0].import_targets.add(route_targets[0], route_targets[1])
|
||||||
|
l2vpns[0].export_targets.add(route_targets[2], route_targets[3])
|
||||||
|
l2vpns[1].import_targets.add(route_targets[4], route_targets[5])
|
||||||
|
l2vpns[1].export_targets.add(route_targets[6], route_targets[7])
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
params = {'q': 'foobar1'}
|
params = {'q': 'foobar1'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
@ -344,6 +392,20 @@ class RouteTargetTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'exporting_vrf': [vrfs[0].rd, vrfs[1].rd]}
|
params = {'exporting_vrf': [vrfs[0].rd, vrfs[1].rd]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
|
||||||
|
def test_importing_l2vpn(self):
|
||||||
|
l2vpns = L2VPN.objects.all()[:2]
|
||||||
|
params = {'importing_l2vpn_id': [l2vpns[0].pk, l2vpns[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
params = {'importing_l2vpn': [l2vpns[0].identifier, l2vpns[1].identifier]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
|
||||||
|
def test_exporting_l2vpn(self):
|
||||||
|
l2vpns = L2VPN.objects.all()[:2]
|
||||||
|
params = {'exporting_l2vpn_id': [l2vpns[0].pk, l2vpns[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
params = {'exporting_l2vpn': [l2vpns[0].identifier, l2vpns[1].identifier]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
|
||||||
def test_tenant(self):
|
def test_tenant(self):
|
||||||
tenants = Tenant.objects.all()[:2]
|
tenants = Tenant.objects.all()[:2]
|
||||||
params = {'tenant_id': [tenants[0].pk, tenants[1].pk]}
|
params = {'tenant_id': [tenants[0].pk, tenants[1].pk]}
|
||||||
@ -922,6 +984,7 @@ class IPRangeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = IPAddress.objects.all()
|
queryset = IPAddress.objects.all()
|
||||||
filterset = IPAddressFilterSet
|
filterset = IPAddressFilterSet
|
||||||
|
ignore_fields = ('fhrpgroup',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1092,6 +1155,16 @@ class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
)
|
)
|
||||||
IPAddress.objects.bulk_create(ipaddresses)
|
IPAddress.objects.bulk_create(ipaddresses)
|
||||||
|
|
||||||
|
services = (
|
||||||
|
Service(name='Service 1', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[1]),
|
||||||
|
Service(name='Service 2', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[1]),
|
||||||
|
Service(name='Service 3', protocol=ServiceProtocolChoices.PROTOCOL_TCP, ports=[1]),
|
||||||
|
)
|
||||||
|
Service.objects.bulk_create(services)
|
||||||
|
services[0].ipaddresses.add(ipaddresses[0])
|
||||||
|
services[1].ipaddresses.add(ipaddresses[1])
|
||||||
|
services[2].ipaddresses.add(ipaddresses[2])
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
params = {'q': 'foobar1'}
|
params = {'q': 'foobar1'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
@ -1231,6 +1304,11 @@ class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
|
params = {'tenant_group': [tenant_groups[0].slug, tenant_groups[1].slug]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
||||||
|
|
||||||
|
def test_service(self):
|
||||||
|
services = Service.objects.all()[:2]
|
||||||
|
params = {'service_id': [services[0].pk, services[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class FHRPGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class FHRPGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = FHRPGroup.objects.all()
|
queryset = FHRPGroup.objects.all()
|
||||||
@ -1475,6 +1553,7 @@ class VLANGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class VLANTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class VLANTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = VLAN.objects.all()
|
queryset = VLAN.objects.all()
|
||||||
filterset = VLANFilterSet
|
filterset = VLANFilterSet
|
||||||
|
ignore_fields = ('interfaces_as_tagged', 'vminterfaces_as_tagged')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1733,6 +1812,7 @@ class VLANTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class ServiceTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class ServiceTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = ServiceTemplate.objects.all()
|
queryset = ServiceTemplate.objects.all()
|
||||||
filterset = ServiceTemplateFilterSet
|
filterset = ServiceTemplateFilterSet
|
||||||
|
ignore_fields = ('ports',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1797,6 +1877,7 @@ class ServiceTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class ServiceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class ServiceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = Service.objects.all()
|
queryset = Service.objects.all()
|
||||||
filterset = ServiceFilterSet
|
filterset = ServiceFilterSet
|
||||||
|
ignore_fields = ('ports',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -1883,9 +1964,9 @@ class ServiceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'virtual_machine': [vms[0].name, vms[1].name]}
|
params = {'virtual_machine': [vms[0].name, vms[1].name]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_ipaddress(self):
|
def test_ip_address(self):
|
||||||
ips = IPAddress.objects.all()[:2]
|
ips = IPAddress.objects.all()[:2]
|
||||||
params = {'ipaddress_id': [ips[0].pk, ips[1].pk]}
|
params = {'ip_address_id': [ips[0].pk, ips[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
params = {'ipaddress': [str(ips[0].address), str(ips[1].address)]}
|
params = {'ip_address': [str(ips[0].address), str(ips[1].address)]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
@ -50,14 +50,14 @@ class ContactGroupFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ContactGroup
|
model = ContactGroup
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class ContactRoleFilterSet(OrganizationalModelFilterSet):
|
class ContactRoleFilterSet(OrganizationalModelFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ContactRole
|
model = ContactRole
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class ContactFilterSet(NetBoxModelFilterSet):
|
class ContactFilterSet(NetBoxModelFilterSet):
|
||||||
@ -77,7 +77,7 @@ class ContactFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Contact
|
model = Contact
|
||||||
fields = ['id', 'name', 'title', 'phone', 'email', 'address', 'link', 'description']
|
fields = ('id', 'name', 'title', 'phone', 'email', 'address', 'link', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -131,7 +131,7 @@ class ContactAssignmentFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ContactAssignment
|
model = ContactAssignment
|
||||||
fields = ['id', 'object_type_id', 'object_id', 'priority', 'tag']
|
fields = ('id', 'object_type_id', 'object_id', 'priority', 'tag')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -192,7 +192,7 @@ class TenantGroupFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TenantGroup
|
model = TenantGroup
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class TenantFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
class TenantFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
||||||
@ -212,7 +212,7 @@ class TenantFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Tenant
|
model = Tenant
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -3,8 +3,10 @@ from django.contrib.auth import get_user_model
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.utils.translation import gettext as _
|
from django.utils.translation import gettext as _
|
||||||
|
|
||||||
|
from core.models import ObjectType
|
||||||
from netbox.filtersets import BaseFilterSet
|
from netbox.filtersets import BaseFilterSet
|
||||||
from users.models import Group, ObjectPermission, Token
|
from users.models import Group, ObjectPermission, Token
|
||||||
|
from utilities.filters import ContentTypeFilter
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'GroupFilterSet',
|
'GroupFilterSet',
|
||||||
@ -19,10 +21,20 @@ class GroupFilterSet(BaseFilterSet):
|
|||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
|
user_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='user',
|
||||||
|
queryset=get_user_model().objects.all(),
|
||||||
|
label=_('User (ID)'),
|
||||||
|
)
|
||||||
|
permission_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='object_permissions',
|
||||||
|
queryset=ObjectPermission.objects.all(),
|
||||||
|
label=_('Permission (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Group
|
model = Group
|
||||||
fields = ['id', 'name']
|
fields = ('id', 'name', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -46,10 +58,18 @@ class UserFilterSet(BaseFilterSet):
|
|||||||
to_field_name='name',
|
to_field_name='name',
|
||||||
label=_('Group (name)'),
|
label=_('Group (name)'),
|
||||||
)
|
)
|
||||||
|
permission_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='object_permissions',
|
||||||
|
queryset=ObjectPermission.objects.all(),
|
||||||
|
label=_('Permission (ID)'),
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = get_user_model()
|
model = get_user_model()
|
||||||
fields = ['id', 'username', 'first_name', 'last_name', 'email', 'is_staff', 'is_active', 'is_superuser']
|
fields = (
|
||||||
|
'id', 'username', 'first_name', 'last_name', 'email', 'date_joined', 'last_login', 'is_staff', 'is_active',
|
||||||
|
'is_superuser',
|
||||||
|
)
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -99,7 +119,7 @@ class TokenFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Token
|
model = Token
|
||||||
fields = ['id', 'key', 'write_enabled', 'description']
|
fields = ('id', 'key', 'write_enabled', 'description', 'last_used')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -115,6 +135,13 @@ class ObjectPermissionFilterSet(BaseFilterSet):
|
|||||||
method='search',
|
method='search',
|
||||||
label=_('Search'),
|
label=_('Search'),
|
||||||
)
|
)
|
||||||
|
object_type_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=ObjectType.objects.all(),
|
||||||
|
field_name='object_types'
|
||||||
|
)
|
||||||
|
object_type = ContentTypeFilter(
|
||||||
|
field_name='object_types'
|
||||||
|
)
|
||||||
can_view = django_filters.BooleanFilter(
|
can_view = django_filters.BooleanFilter(
|
||||||
method='_check_action'
|
method='_check_action'
|
||||||
)
|
)
|
||||||
@ -152,7 +179,7 @@ class ObjectPermissionFilterSet(BaseFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ObjectPermission
|
model = ObjectPermission
|
||||||
fields = ['id', 'name', 'enabled', 'object_types', 'description']
|
fields = ('id', 'name', 'enabled', 'object_types', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -15,6 +15,7 @@ User = get_user_model()
|
|||||||
class UserTestCase(TestCase, BaseFilterSetTests):
|
class UserTestCase(TestCase, BaseFilterSetTests):
|
||||||
queryset = User.objects.all()
|
queryset = User.objects.all()
|
||||||
filterset = filtersets.UserFilterSet
|
filterset = filtersets.UserFilterSet
|
||||||
|
ignore_fields = ('config', 'dashboard', 'password', 'user_permissions')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -66,6 +67,16 @@ class UserTestCase(TestCase, BaseFilterSetTests):
|
|||||||
users[1].groups.set([groups[1]])
|
users[1].groups.set([groups[1]])
|
||||||
users[2].groups.set([groups[2]])
|
users[2].groups.set([groups[2]])
|
||||||
|
|
||||||
|
object_permissions = (
|
||||||
|
ObjectPermission(name='Permission 1', actions=['add']),
|
||||||
|
ObjectPermission(name='Permission 2', actions=['change']),
|
||||||
|
ObjectPermission(name='Permission 3', actions=['delete']),
|
||||||
|
)
|
||||||
|
ObjectPermission.objects.bulk_create(object_permissions)
|
||||||
|
object_permissions[0].users.add(users[0])
|
||||||
|
object_permissions[1].users.add(users[1])
|
||||||
|
object_permissions[2].users.add(users[2])
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
params = {'q': 'user1'}
|
params = {'q': 'user1'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
@ -105,10 +116,16 @@ class UserTestCase(TestCase, BaseFilterSetTests):
|
|||||||
params = {'group': [groups[0].name, groups[1].name]}
|
params = {'group': [groups[0].name, groups[1].name]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_permission(self):
|
||||||
|
object_permissions = ObjectPermission.objects.all()[:2]
|
||||||
|
params = {'permission_id': [object_permissions[0].pk, object_permissions[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class GroupTestCase(TestCase, BaseFilterSetTests):
|
class GroupTestCase(TestCase, BaseFilterSetTests):
|
||||||
queryset = Group.objects.all()
|
queryset = Group.objects.all()
|
||||||
filterset = filtersets.GroupFilterSet
|
filterset = filtersets.GroupFilterSet
|
||||||
|
ignore_fields = ('permissions',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -120,6 +137,26 @@ class GroupTestCase(TestCase, BaseFilterSetTests):
|
|||||||
)
|
)
|
||||||
Group.objects.bulk_create(groups)
|
Group.objects.bulk_create(groups)
|
||||||
|
|
||||||
|
users = (
|
||||||
|
User(username='User 1'),
|
||||||
|
User(username='User 2'),
|
||||||
|
User(username='User 3'),
|
||||||
|
)
|
||||||
|
User.objects.bulk_create(users)
|
||||||
|
users[0].groups.set([groups[0]])
|
||||||
|
users[1].groups.set([groups[1]])
|
||||||
|
users[2].groups.set([groups[2]])
|
||||||
|
|
||||||
|
object_permissions = (
|
||||||
|
ObjectPermission(name='Permission 1', actions=['add']),
|
||||||
|
ObjectPermission(name='Permission 2', actions=['change']),
|
||||||
|
ObjectPermission(name='Permission 3', actions=['delete']),
|
||||||
|
)
|
||||||
|
ObjectPermission.objects.bulk_create(object_permissions)
|
||||||
|
object_permissions[0].groups.add(groups[0])
|
||||||
|
object_permissions[1].groups.add(groups[1])
|
||||||
|
object_permissions[2].groups.add(groups[2])
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
params = {'q': 'group 1'}
|
params = {'q': 'group 1'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
@ -128,10 +165,21 @@ class GroupTestCase(TestCase, BaseFilterSetTests):
|
|||||||
params = {'name': ['Group 1', 'Group 2']}
|
params = {'name': ['Group 1', 'Group 2']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_user(self):
|
||||||
|
users = User.objects.all()[:2]
|
||||||
|
params = {'user_id': [users[0].pk, users[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_permission(self):
|
||||||
|
object_permissions = ObjectPermission.objects.all()[:2]
|
||||||
|
params = {'permission_id': [object_permissions[0].pk, object_permissions[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class ObjectPermissionTestCase(TestCase, BaseFilterSetTests):
|
class ObjectPermissionTestCase(TestCase, BaseFilterSetTests):
|
||||||
queryset = ObjectPermission.objects.all()
|
queryset = ObjectPermission.objects.all()
|
||||||
filterset = filtersets.ObjectPermissionFilterSet
|
filterset = filtersets.ObjectPermissionFilterSet
|
||||||
|
ignore_fields = ('actions', 'constraints')
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
@ -226,6 +274,7 @@ class ObjectPermissionTestCase(TestCase, BaseFilterSetTests):
|
|||||||
class TokenTestCase(TestCase, BaseFilterSetTests):
|
class TokenTestCase(TestCase, BaseFilterSetTests):
|
||||||
queryset = Token.objects.all()
|
queryset = Token.objects.all()
|
||||||
filterset = filtersets.TokenFilterSet
|
filterset = filtersets.TokenFilterSet
|
||||||
|
ignore_fields = ('allowed_ips',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -1,15 +1,91 @@
|
|||||||
from datetime import date, datetime, timezone
|
import django_filters
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
from itertools import chain
|
||||||
|
from mptt.models import MPTTModel
|
||||||
|
|
||||||
|
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
|
from django.db.models import ForeignKey, ManyToManyField, ManyToManyRel, ManyToOneRel, OneToOneRel
|
||||||
|
from django.utils.module_loading import import_string
|
||||||
|
from taggit.managers import TaggableManager
|
||||||
|
|
||||||
|
from extras.filters import TagFilter
|
||||||
|
from utilities.filters import ContentTypeFilter, TreeNodeMultipleChoiceFilter
|
||||||
|
|
||||||
|
from core.models import ObjectType
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'BaseFilterSetTests',
|
'BaseFilterSetTests',
|
||||||
'ChangeLoggedFilterSetTests',
|
'ChangeLoggedFilterSetTests',
|
||||||
)
|
)
|
||||||
|
|
||||||
|
EXEMPT_MODEL_FIELDS = (
|
||||||
|
'comments',
|
||||||
|
'custom_field_data',
|
||||||
|
'level', # MPTT
|
||||||
|
'lft', # MPTT
|
||||||
|
'rght', # MPTT
|
||||||
|
'tree_id', # MPTT
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class BaseFilterSetTests:
|
class BaseFilterSetTests:
|
||||||
queryset = None
|
queryset = None
|
||||||
filterset = None
|
filterset = None
|
||||||
|
ignore_fields = tuple()
|
||||||
|
|
||||||
|
def get_m2m_filter_name(self, field):
|
||||||
|
"""
|
||||||
|
Given a ManyToManyField, determine the correct name for its corresponding Filter. Individual test
|
||||||
|
cases may override this method to prescribe deviations for specific fields.
|
||||||
|
"""
|
||||||
|
related_model_name = field.related_model._meta.verbose_name
|
||||||
|
return related_model_name.lower().replace(' ', '_')
|
||||||
|
|
||||||
|
def get_filters_for_model_field(self, field):
|
||||||
|
"""
|
||||||
|
Given a model field, return an iterable of (name, class) for each filter that should be defined on
|
||||||
|
the model's FilterSet class. If the appropriate filter class cannot be determined, it will be None.
|
||||||
|
"""
|
||||||
|
# ForeignKey & OneToOneField
|
||||||
|
if issubclass(field.__class__, ForeignKey) or type(field) is OneToOneRel:
|
||||||
|
|
||||||
|
# Relationships to ContentType (used as part of a GFK) do not need a filter
|
||||||
|
if field.related_model is ContentType:
|
||||||
|
return [(None, None)]
|
||||||
|
|
||||||
|
# ForeignKeys to ObjectType need two filters: 'app.model' & PK
|
||||||
|
if field.related_model is ObjectType:
|
||||||
|
return [
|
||||||
|
(field.name, ContentTypeFilter),
|
||||||
|
(f'{field.name}_id', django_filters.ModelMultipleChoiceFilter),
|
||||||
|
]
|
||||||
|
|
||||||
|
# ForeignKey to an MPTT-enabled model
|
||||||
|
if issubclass(field.related_model, MPTTModel) and field.model is not field.related_model:
|
||||||
|
return [(f'{field.name}_id', TreeNodeMultipleChoiceFilter)]
|
||||||
|
|
||||||
|
return [(f'{field.name}_id', django_filters.ModelMultipleChoiceFilter)]
|
||||||
|
|
||||||
|
# Many-to-many relationships (forward & backward)
|
||||||
|
elif type(field) in (ManyToManyField, ManyToManyRel):
|
||||||
|
filter_name = self.get_m2m_filter_name(field)
|
||||||
|
|
||||||
|
# ManyToManyFields to ObjectType need two filters: 'app.model' & PK
|
||||||
|
if field.related_model is ObjectType:
|
||||||
|
return [
|
||||||
|
(filter_name, ContentTypeFilter),
|
||||||
|
(f'{filter_name}_id', django_filters.ModelMultipleChoiceFilter),
|
||||||
|
]
|
||||||
|
|
||||||
|
return [(f'{filter_name}_id', django_filters.ModelMultipleChoiceFilter)]
|
||||||
|
|
||||||
|
# Tag manager
|
||||||
|
if type(field) is TaggableManager:
|
||||||
|
return [('tag', TagFilter)]
|
||||||
|
|
||||||
|
# Unable to determine the correct filter class
|
||||||
|
return [(field.name, None)]
|
||||||
|
|
||||||
def test_id(self):
|
def test_id(self):
|
||||||
"""
|
"""
|
||||||
@ -19,6 +95,61 @@ class BaseFilterSetTests:
|
|||||||
self.assertGreater(self.queryset.count(), 2)
|
self.assertGreater(self.queryset.count(), 2)
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_missing_filters(self):
|
||||||
|
"""
|
||||||
|
Check for any model fields which do not have the required filter(s) defined.
|
||||||
|
"""
|
||||||
|
app_label = self.__class__.__module__.split('.')[0]
|
||||||
|
model = self.queryset.model
|
||||||
|
model_name = model.__name__
|
||||||
|
|
||||||
|
# Import the FilterSet class & sanity check it
|
||||||
|
filterset = import_string(f'{app_label}.filtersets.{model_name}FilterSet')
|
||||||
|
self.assertEqual(model, filterset.Meta.model, "FilterSet model does not match!")
|
||||||
|
|
||||||
|
filters = filterset.get_filters()
|
||||||
|
|
||||||
|
# Check for missing filters
|
||||||
|
for model_field in model._meta.get_fields():
|
||||||
|
|
||||||
|
# Skip private fields
|
||||||
|
if model_field.name.startswith('_'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip ignored fields
|
||||||
|
if model_field.name in chain(self.ignore_fields, EXEMPT_MODEL_FIELDS):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip reverse ForeignKey relationships
|
||||||
|
if type(model_field) is ManyToOneRel:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip generic relationships
|
||||||
|
if type(model_field) in (GenericForeignKey, GenericRelation):
|
||||||
|
continue
|
||||||
|
|
||||||
|
for filter_name, filter_class in self.get_filters_for_model_field(model_field):
|
||||||
|
|
||||||
|
if filter_name is None:
|
||||||
|
# Field is exempt
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Check that the filter is defined
|
||||||
|
self.assertIn(
|
||||||
|
filter_name,
|
||||||
|
filters.keys(),
|
||||||
|
f'No filter defined for {filter_name} ({model_field.name})!'
|
||||||
|
)
|
||||||
|
|
||||||
|
# Check that the filter class is correct
|
||||||
|
filter = filters[filter_name]
|
||||||
|
if filter_class is not None:
|
||||||
|
self.assertIs(
|
||||||
|
type(filter),
|
||||||
|
filter_class,
|
||||||
|
f"Invalid filter class {type(filter)} for {filter_name} (should be {filter_class})!"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class ChangeLoggedFilterSetTests(BaseFilterSetTests):
|
class ChangeLoggedFilterSetTests(BaseFilterSetTests):
|
||||||
|
|
||||||
|
@ -27,14 +27,14 @@ class ClusterTypeFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClusterType
|
model = ClusterType
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class ClusterGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
|
class ClusterGroupFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet):
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = ClusterGroup
|
model = ClusterGroup
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class ClusterFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
|
class ClusterFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
|
||||||
@ -101,7 +101,7 @@ class ClusterFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilte
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Cluster
|
model = Cluster
|
||||||
fields = ['id', 'name', 'description']
|
fields = ('id', 'name', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -240,7 +240,7 @@ class VirtualMachineFilterSet(
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualMachine
|
model = VirtualMachine
|
||||||
fields = ['id', 'cluster', 'vcpus', 'memory', 'disk', 'description']
|
fields = ('id', 'cluster', 'vcpus', 'memory', 'disk', 'description', 'interface_count', 'virtual_disk_count')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -299,7 +299,7 @@ class VMInterfaceFilterSet(NetBoxModelFilterSet, CommonInterfaceFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VMInterface
|
model = VMInterface
|
||||||
fields = ['id', 'name', 'enabled', 'mtu', 'description']
|
fields = ('id', 'name', 'enabled', 'mtu', 'mode', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -325,7 +325,7 @@ class VirtualDiskFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = VirtualDisk
|
model = VirtualDisk
|
||||||
fields = ['id', 'name', 'size', 'description']
|
fields = ('id', 'name', 'size', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -522,6 +522,7 @@ class VirtualMachineTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
class VMInterfaceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class VMInterfaceTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = VMInterface.objects.all()
|
queryset = VMInterface.objects.all()
|
||||||
filterset = VMInterfaceFilterSet
|
filterset = VMInterfaceFilterSet
|
||||||
|
ignore_fields = ('tagged_vlans', 'untagged_vlan',)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
@ -29,7 +29,7 @@ class TunnelGroupFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TunnelGroup
|
model = TunnelGroup
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class TunnelFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
class TunnelFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||||
@ -62,7 +62,7 @@ class TunnelFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Tunnel
|
model = Tunnel
|
||||||
fields = ['id', 'name', 'tunnel_id', 'description']
|
fields = ('id', 'name', 'tunnel_id', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -120,10 +120,21 @@ class TunnelTerminationFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = TunnelTermination
|
model = TunnelTermination
|
||||||
fields = ['id']
|
fields = ('id', 'termination_id')
|
||||||
|
|
||||||
|
|
||||||
class IKEProposalFilterSet(NetBoxModelFilterSet):
|
class IKEProposalFilterSet(NetBoxModelFilterSet):
|
||||||
|
ike_policy_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='ike_policies',
|
||||||
|
queryset=IKEPolicy.objects.all(),
|
||||||
|
label=_('IKE policy (ID)'),
|
||||||
|
)
|
||||||
|
ike_policy = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='ike_policies__name',
|
||||||
|
queryset=IKEPolicy.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
label=_('IKE policy (name)'),
|
||||||
|
)
|
||||||
authentication_method = django_filters.MultipleChoiceFilter(
|
authentication_method = django_filters.MultipleChoiceFilter(
|
||||||
choices=AuthenticationMethodChoices
|
choices=AuthenticationMethodChoices
|
||||||
)
|
)
|
||||||
@ -139,7 +150,7 @@ class IKEProposalFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IKEProposal
|
model = IKEProposal
|
||||||
fields = ['id', 'name', 'sa_lifetime', 'description']
|
fields = ('id', 'name', 'sa_lifetime', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -158,16 +169,23 @@ class IKEPolicyFilterSet(NetBoxModelFilterSet):
|
|||||||
mode = django_filters.MultipleChoiceFilter(
|
mode = django_filters.MultipleChoiceFilter(
|
||||||
choices=IKEModeChoices
|
choices=IKEModeChoices
|
||||||
)
|
)
|
||||||
proposal_id = MultiValueNumberFilter(
|
ike_proposal_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='proposals__id'
|
field_name='proposals',
|
||||||
|
queryset=IKEProposal.objects.all()
|
||||||
)
|
)
|
||||||
proposal = MultiValueCharFilter(
|
ike_proposal = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='proposals__name'
|
field_name='proposals__name',
|
||||||
|
queryset=IKEProposal.objects.all(),
|
||||||
|
to_field_name='name'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Remove in v4.1
|
||||||
|
proposal = ike_proposal
|
||||||
|
proposal_id = ike_proposal_id
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IKEPolicy
|
model = IKEPolicy
|
||||||
fields = ['id', 'name', 'preshared_key', 'description']
|
fields = ('id', 'name', 'preshared_key', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -180,6 +198,17 @@ class IKEPolicyFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
|
|
||||||
class IPSecProposalFilterSet(NetBoxModelFilterSet):
|
class IPSecProposalFilterSet(NetBoxModelFilterSet):
|
||||||
|
ipsec_policy_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='ipsec_policies',
|
||||||
|
queryset=IPSecPolicy.objects.all(),
|
||||||
|
label=_('IPSec policy (ID)'),
|
||||||
|
)
|
||||||
|
ipsec_policy = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
field_name='ipsec_policies__name',
|
||||||
|
queryset=IPSecPolicy.objects.all(),
|
||||||
|
to_field_name='name',
|
||||||
|
label=_('IPSec policy (name)'),
|
||||||
|
)
|
||||||
encryption_algorithm = django_filters.MultipleChoiceFilter(
|
encryption_algorithm = django_filters.MultipleChoiceFilter(
|
||||||
choices=EncryptionAlgorithmChoices
|
choices=EncryptionAlgorithmChoices
|
||||||
)
|
)
|
||||||
@ -189,7 +218,7 @@ class IPSecProposalFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPSecProposal
|
model = IPSecProposal
|
||||||
fields = ['id', 'name', 'sa_lifetime_seconds', 'sa_lifetime_data', 'description']
|
fields = ('id', 'name', 'sa_lifetime_seconds', 'sa_lifetime_data', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -205,16 +234,23 @@ class IPSecPolicyFilterSet(NetBoxModelFilterSet):
|
|||||||
pfs_group = django_filters.MultipleChoiceFilter(
|
pfs_group = django_filters.MultipleChoiceFilter(
|
||||||
choices=DHGroupChoices
|
choices=DHGroupChoices
|
||||||
)
|
)
|
||||||
proposal_id = MultiValueNumberFilter(
|
ipsec_proposal_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='proposals__id'
|
field_name='proposals',
|
||||||
|
queryset=IPSecProposal.objects.all()
|
||||||
)
|
)
|
||||||
proposal = MultiValueCharFilter(
|
ipsec_proposal = django_filters.ModelMultipleChoiceFilter(
|
||||||
field_name='proposals__name'
|
field_name='proposals__name',
|
||||||
|
queryset=IPSecProposal.objects.all(),
|
||||||
|
to_field_name='name'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# TODO: Remove in v4.1
|
||||||
|
proposal = ipsec_proposal
|
||||||
|
proposal_id = ipsec_proposal_id
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPSecPolicy
|
model = IPSecPolicy
|
||||||
fields = ['id', 'name', 'description']
|
fields = ('id', 'name', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -253,7 +289,7 @@ class IPSecProfileFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = IPSecProfile
|
model = IPSecProfile
|
||||||
fields = ['id', 'name', 'description']
|
fields = ('id', 'name', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -295,7 +331,7 @@ class L2VPNFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = L2VPN
|
model = L2VPN
|
||||||
fields = ['id', 'identifier', 'name', 'slug', 'type', 'description']
|
fields = ('id', 'identifier', 'name', 'slug', 'type', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -402,7 +438,7 @@ class L2VPNTerminationFilterSet(NetBoxModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = L2VPNTermination
|
model = L2VPNTermination
|
||||||
fields = ('id', 'assigned_object_type_id')
|
fields = ('id', 'assigned_object_id')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
from django.contrib.contenttypes.models import ContentType
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
|
|
||||||
from dcim.choices import InterfaceTypeChoices
|
from dcim.choices import InterfaceTypeChoices
|
||||||
@ -331,6 +330,16 @@ class IKEProposalTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
)
|
)
|
||||||
IKEProposal.objects.bulk_create(ike_proposals)
|
IKEProposal.objects.bulk_create(ike_proposals)
|
||||||
|
|
||||||
|
ike_policies = (
|
||||||
|
IKEPolicy(name='IKE Policy 1'),
|
||||||
|
IKEPolicy(name='IKE Policy 2'),
|
||||||
|
IKEPolicy(name='IKE Policy 3'),
|
||||||
|
)
|
||||||
|
IKEPolicy.objects.bulk_create(ike_policies)
|
||||||
|
ike_policies[0].proposals.add(ike_proposals[0])
|
||||||
|
ike_policies[1].proposals.add(ike_proposals[1])
|
||||||
|
ike_policies[2].proposals.add(ike_proposals[2])
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
params = {'q': 'foobar1'}
|
params = {'q': 'foobar1'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
@ -343,6 +352,13 @@ class IKEProposalTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'description': ['foobar1', 'foobar2']}
|
params = {'description': ['foobar1', 'foobar2']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_ike_policy(self):
|
||||||
|
ike_policies = IKEPolicy.objects.all()[:2]
|
||||||
|
params = {'ike_policy_id': [ike_policies[0].pk, ike_policies[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
params = {'ike_policy': [ike_policies[0].name, ike_policies[1].name]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_authentication_method(self):
|
def test_authentication_method(self):
|
||||||
params = {'authentication_method': [
|
params = {'authentication_method': [
|
||||||
AuthenticationMethodChoices.PRESHARED_KEYS, AuthenticationMethodChoices.CERTIFICATES
|
AuthenticationMethodChoices.PRESHARED_KEYS, AuthenticationMethodChoices.CERTIFICATES
|
||||||
@ -446,11 +462,11 @@ class IKEPolicyTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'mode': [IKEModeChoices.MAIN]}
|
params = {'mode': [IKEModeChoices.MAIN]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_proposal(self):
|
def test_ike_proposal(self):
|
||||||
proposals = IKEProposal.objects.all()[:2]
|
proposals = IKEProposal.objects.all()[:2]
|
||||||
params = {'proposal_id': [proposals[0].pk, proposals[1].pk]}
|
params = {'ike_proposal_id': [proposals[0].pk, proposals[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
params = {'proposal': [proposals[0].name, proposals[1].name]}
|
params = {'ike_proposal': [proposals[0].name, proposals[1].name]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
@ -488,6 +504,16 @@ class IPSecProposalTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
)
|
)
|
||||||
IPSecProposal.objects.bulk_create(ipsec_proposals)
|
IPSecProposal.objects.bulk_create(ipsec_proposals)
|
||||||
|
|
||||||
|
ipsec_policies = (
|
||||||
|
IPSecPolicy(name='IPSec Policy 1'),
|
||||||
|
IPSecPolicy(name='IPSec Policy 2'),
|
||||||
|
IPSecPolicy(name='IPSec Policy 3'),
|
||||||
|
)
|
||||||
|
IPSecPolicy.objects.bulk_create(ipsec_policies)
|
||||||
|
ipsec_policies[0].proposals.add(ipsec_proposals[0])
|
||||||
|
ipsec_policies[1].proposals.add(ipsec_proposals[1])
|
||||||
|
ipsec_policies[2].proposals.add(ipsec_proposals[2])
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
params = {'q': 'foobar1'}
|
params = {'q': 'foobar1'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
@ -500,6 +526,13 @@ class IPSecProposalTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'description': ['foobar1', 'foobar2']}
|
params = {'description': ['foobar1', 'foobar2']}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_ipsec_policy(self):
|
||||||
|
ipsec_policies = IPSecPolicy.objects.all()[:2]
|
||||||
|
params = {'ipsec_policy_id': [ipsec_policies[0].pk, ipsec_policies[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
params = {'ipsec_policy': [ipsec_policies[0].name, ipsec_policies[1].name]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_encryption_algorithm(self):
|
def test_encryption_algorithm(self):
|
||||||
params = {'encryption_algorithm': [
|
params = {'encryption_algorithm': [
|
||||||
EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC, EncryptionAlgorithmChoices.ENCRYPTION_AES192_CBC
|
EncryptionAlgorithmChoices.ENCRYPTION_AES128_CBC, EncryptionAlgorithmChoices.ENCRYPTION_AES192_CBC
|
||||||
@ -584,11 +617,11 @@ class IPSecPolicyTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'pfs_group': [DHGroupChoices.GROUP_1, DHGroupChoices.GROUP_2]}
|
params = {'pfs_group': [DHGroupChoices.GROUP_1, DHGroupChoices.GROUP_2]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
def test_proposal(self):
|
def test_ipsec_proposal(self):
|
||||||
proposals = IPSecProposal.objects.all()[:2]
|
proposals = IPSecProposal.objects.all()[:2]
|
||||||
params = {'proposal_id': [proposals[0].pk, proposals[1].pk]}
|
params = {'ipsec_proposal_id': [proposals[0].pk, proposals[1].pk]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
params = {'proposal': [proposals[0].name, proposals[1].name]}
|
params = {'ipsec_proposal': [proposals[0].name, proposals[1].name]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
@ -710,6 +743,14 @@ class L2VPNTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
queryset = L2VPN.objects.all()
|
queryset = L2VPN.objects.all()
|
||||||
filterset = L2VPNFilterSet
|
filterset = L2VPNFilterSet
|
||||||
|
|
||||||
|
def get_m2m_filter_name(self, field):
|
||||||
|
# Override filter names for import & export RouteTargets
|
||||||
|
if field.name == 'import_targets':
|
||||||
|
return 'import_target'
|
||||||
|
if field.name == 'export_targets':
|
||||||
|
return 'export_target'
|
||||||
|
return ChangeLoggedFilterSetTests.get_m2m_filter_name(field)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
|
|
||||||
@ -848,8 +889,8 @@ class L2VPNTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'l2vpn': [l2vpns[0].slug, l2vpns[1].slug]}
|
params = {'l2vpn': [l2vpns[0].slug, l2vpns[1].slug]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
|
||||||
|
|
||||||
def test_content_type(self):
|
def test_termination_type(self):
|
||||||
params = {'assigned_object_type_id': ContentType.objects.get(model='vlan').pk}
|
params = {'assigned_object_type': 'ipam.vlan'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||||
|
|
||||||
def test_interface(self):
|
def test_interface(self):
|
||||||
|
@ -2,6 +2,7 @@ import django_filters
|
|||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
|
|
||||||
from dcim.choices import LinkStatusChoices
|
from dcim.choices import LinkStatusChoices
|
||||||
|
from dcim.models import Interface
|
||||||
from ipam.models import VLAN
|
from ipam.models import VLAN
|
||||||
from netbox.filtersets import OrganizationalModelFilterSet, NetBoxModelFilterSet
|
from netbox.filtersets import OrganizationalModelFilterSet, NetBoxModelFilterSet
|
||||||
from tenancy.filtersets import TenancyFilterSet
|
from tenancy.filtersets import TenancyFilterSet
|
||||||
@ -39,7 +40,7 @@ class WirelessLANGroupFilterSet(OrganizationalModelFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WirelessLANGroup
|
model = WirelessLANGroup
|
||||||
fields = ['id', 'name', 'slug', 'description']
|
fields = ('id', 'name', 'slug', 'description')
|
||||||
|
|
||||||
|
|
||||||
class WirelessLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
class WirelessLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||||
@ -60,6 +61,10 @@ class WirelessLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
vlan_id = django_filters.ModelMultipleChoiceFilter(
|
vlan_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
queryset=VLAN.objects.all()
|
queryset=VLAN.objects.all()
|
||||||
)
|
)
|
||||||
|
interface_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=Interface.objects.all(),
|
||||||
|
field_name='interfaces'
|
||||||
|
)
|
||||||
auth_type = django_filters.MultipleChoiceFilter(
|
auth_type = django_filters.MultipleChoiceFilter(
|
||||||
choices=WirelessAuthTypeChoices
|
choices=WirelessAuthTypeChoices
|
||||||
)
|
)
|
||||||
@ -69,7 +74,7 @@ class WirelessLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WirelessLAN
|
model = WirelessLAN
|
||||||
fields = ['id', 'ssid', 'auth_psk', 'description']
|
fields = ('id', 'ssid', 'auth_psk', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
@ -82,8 +87,12 @@ class WirelessLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
|
|
||||||
class WirelessLinkFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
class WirelessLinkFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
||||||
interface_a_id = MultiValueNumberFilter()
|
interface_a_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
interface_b_id = MultiValueNumberFilter()
|
queryset=Interface.objects.all()
|
||||||
|
)
|
||||||
|
interface_b_id = django_filters.ModelMultipleChoiceFilter(
|
||||||
|
queryset=Interface.objects.all()
|
||||||
|
)
|
||||||
status = django_filters.MultipleChoiceFilter(
|
status = django_filters.MultipleChoiceFilter(
|
||||||
choices=LinkStatusChoices
|
choices=LinkStatusChoices
|
||||||
)
|
)
|
||||||
@ -96,7 +105,7 @@ class WirelessLinkFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
|
|||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = WirelessLink
|
model = WirelessLink
|
||||||
fields = ['id', 'ssid', 'auth_psk', 'description']
|
fields = ('id', 'ssid', 'auth_psk', 'description')
|
||||||
|
|
||||||
def search(self, queryset, name, value):
|
def search(self, queryset, name, value):
|
||||||
if not value.strip():
|
if not value.strip():
|
||||||
|
@ -153,6 +153,17 @@ class WirelessLANTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
)
|
)
|
||||||
WirelessLAN.objects.bulk_create(wireless_lans)
|
WirelessLAN.objects.bulk_create(wireless_lans)
|
||||||
|
|
||||||
|
device = create_test_device('Device 1')
|
||||||
|
interfaces = (
|
||||||
|
Interface(device=device, name='Interface 1', type=InterfaceTypeChoices.TYPE_80211N),
|
||||||
|
Interface(device=device, name='Interface 2', type=InterfaceTypeChoices.TYPE_80211N),
|
||||||
|
Interface(device=device, name='Interface 3', type=InterfaceTypeChoices.TYPE_80211N),
|
||||||
|
)
|
||||||
|
Interface.objects.bulk_create(interfaces)
|
||||||
|
interfaces[0].wireless_lans.add(wireless_lans[0])
|
||||||
|
interfaces[1].wireless_lans.add(wireless_lans[1])
|
||||||
|
interfaces[2].wireless_lans.add(wireless_lans[2])
|
||||||
|
|
||||||
def test_q(self):
|
def test_q(self):
|
||||||
params = {'q': 'foobar1'}
|
params = {'q': 'foobar1'}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||||
@ -200,6 +211,11 @@ class WirelessLANTestCase(TestCase, ChangeLoggedFilterSetTests):
|
|||||||
params = {'tenant': [tenants[0].slug, tenants[1].slug]}
|
params = {'tenant': [tenants[0].slug, tenants[1].slug]}
|
||||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
def test_interface(self):
|
||||||
|
interfaces = Interface.objects.all()[:2]
|
||||||
|
params = {'interface_id': [interfaces[0].pk, interfaces[1].pk]}
|
||||||
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||||
|
|
||||||
|
|
||||||
class WirelessLinkTestCase(TestCase, ChangeLoggedFilterSetTests):
|
class WirelessLinkTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||||
queryset = WirelessLink.objects.all()
|
queryset = WirelessLink.objects.all()
|
||||||
|
Loading…
Reference in New Issue
Block a user