1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Merge branch 'develop' into feature

This commit is contained in:
jeremystretch
2021-05-04 14:25:53 -04:00
53 changed files with 1172 additions and 1309 deletions

View File

@ -5,21 +5,25 @@ labels: ["type: bug"]
body: body:
- type: markdown - type: markdown
attributes: attributes:
value: "**NOTE:** This form is only for reporting _reproducible bugs_ in a value: >
current NetBox installation. If you're having trouble with installation or just **NOTE:** This form is only for reporting _reproducible bugs_ in a current NetBox
looking for assistance with using NetBox, please visit our installation. If you're having trouble with installation or just looking for
[discussion forum](https://github.com/netbox-community/netbox/discussions) instead." assistance with using NetBox, please visit our
[discussion forum](https://github.com/netbox-community/netbox/discussions) instead.
- type: input - type: input
attributes: attributes:
label: NetBox version label: NetBox version
description: "What version of NetBox are you currently running?" description: >
placeholder: v2.10.4 What version of NetBox are you currently running? (If you don't have access to the most
recent NetBox release, consider testing on our [demo instance](https://demo.netbox.dev/)
before opening a bug report to see if your issue has already been addressed.)
placeholder: v2.11.2
validations: validations:
required: true required: true
- type: dropdown - type: dropdown
attributes: attributes:
label: Python version label: Python version
description: "What version of Python are you currently running?" description: What version of Python are you currently running?
options: options:
- 3.6 - 3.6
- 3.7 - 3.7
@ -30,12 +34,13 @@ body:
- type: textarea - type: textarea
attributes: attributes:
label: Steps to Reproduce label: Steps to Reproduce
description: "Describe in detail the exact steps that someone else can take to description: >
reproduce this bug using the current stable release of NetBox. Begin with the Describe in detail the exact steps that someone else can take to
creation of any necessary database objects and call out every operation being reproduce this bug using the current stable release of NetBox. Begin with the
performed explicitly. If reporting a bug in the REST API, be sure to reconstruct creation of any necessary database objects and call out every operation being
the raw HTTP request(s) being made: Don't rely on a client library such as performed explicitly. If reporting a bug in the REST API, be sure to reconstruct
pynetbox." the raw HTTP request(s) being made: Don't rely on a client library such as
pynetbox."
placeholder: | placeholder: |
1. Click on "create widget" 1. Click on "create widget"
2. Set foo to 12 and bar to G 2. Set foo to 12 and bar to G
@ -45,14 +50,14 @@ body:
- type: textarea - type: textarea
attributes: attributes:
label: Expected Behavior label: Expected Behavior
description: "What did you expect to happen?" description: What did you expect to happen?
placeholder: "A new widget should have been created with the specified attributes" placeholder: A new widget should have been created with the specified attributes
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: Observed Behavior label: Observed Behavior
description: "What happened instead?" description: What happened instead?
placeholder: "A TypeError exception was raised" placeholder: A TypeError exception was raised
validations: validations:
required: true required: true

View File

@ -30,6 +30,6 @@ body:
- type: textarea - type: textarea
attributes: attributes:
label: Proposed Changes label: Proposed Changes
description: "Describe the proposed changes and why they are necessary" description: Describe the proposed changes and why they are necessary.
validations: validations:
required: true required: true

View File

@ -5,14 +5,15 @@ labels: ["type: feature"]
body: body:
- type: markdown - type: markdown
attributes: attributes:
value: "**NOTE:** This form is only for submitting well-formed proposals to extend or value: >
modify NetBox in some way. If you're trying to solve a problem but can't figure out how, **NOTE:** This form is only for submitting well-formed proposals to extend or modify
or if you still need time to work on the details of a proposed new feature, please start NetBox in some way. If you're trying to solve a problem but can't figure out how, or if
a [discussion](https://github.com/netbox-community/netbox/discussions) instead." you still need time to work on the details of a proposed new feature, please start a
[discussion](https://github.com/netbox-community/netbox/discussions) instead.
- type: input - type: input
attributes: attributes:
label: NetBox version label: NetBox version
description: "What version of NetBox are you currently running?" description: What version of NetBox are you currently running?
placeholder: v2.10.4 placeholder: v2.10.4
validations: validations:
required: true required: true
@ -28,26 +29,29 @@ body:
- type: textarea - type: textarea
attributes: attributes:
label: Proposed functionality label: Proposed functionality
description: "Describe in detail the new feature or behavior you'd like to propose. description: >
Include any specific changes to work flows, data models, or the user interface." Describe in detail the new feature or behavior you'd like to propose. Include any specific
changes to work flows, data models, or the user interface.
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: Use case label: Use case
description: "Explain how adding this functionality would benefit NetBox users. What description: >
need does it address?" Explain how adding this functionality would benefit NetBox users. What need does it address?
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: Database changes label: Database changes
description: "Note any changes to the database schema necessary to support the new description: >
feature. For example, does the proposal require adding a new model or field? (Not Note any changes to the database schema necessary to support the new feature. For example,
all new features require database changes.)" does the proposal require adding a new model or field? (Not all new features require database
changes.)
- type: textarea - type: textarea
attributes: attributes:
label: External dependencies label: External dependencies
description: "List any new dependencies on external libraries or services that this description: >
new feature would introduce. For example, does the proposal require the installation List any new dependencies on external libraries or services that this new feature would
of a new Python package? (Not all new features introduce new dependencies.)" introduce. For example, does the proposal require the installation of a new Python package?
(Not all new features introduce new dependencies.)

View File

@ -5,18 +5,20 @@ labels: ["type: housekeeping"]
body: body:
- type: markdown - type: markdown
attributes: attributes:
value: "**NOTE:** This template is for use by maintainers only. Please do not submit value: >
an issue using this template unless you have been specifically asked to do so." **NOTE:** This template is for use by maintainers only. Please do not submit
an issue using this template unless you have been specifically asked to do so.
- type: textarea - type: textarea
attributes: attributes:
label: Proposed Changes label: Proposed Changes
description: "Describe in detail the new feature or behavior you'd like to propose. description: >
Include any specific changes to work flows, data models, or the user interface." Describe in detail the new feature or behavior you'd like to propose.
Include any specific changes to work flows, data models, or the user interface.
validations: validations:
required: true required: true
- type: textarea - type: textarea
attributes: attributes:
label: Justification label: Justification
description: "Please provide justification for the proposed change(s)." description: Please provide justification for the proposed change(s).
validations: validations:
required: true required: true

View File

@ -20,6 +20,7 @@ jobs:
days-before-stale: 45 days-before-stale: 45
days-before-close: 15 days-before-close: 15
exempt-issue-labels: 'status: accepted,status: blocked,status: needs milestone' exempt-issue-labels: 'status: accepted,status: blocked,status: needs milestone'
operations-per-run: 100
remove-stale-when-updated: false remove-stale-when-updated: false
stale-issue-label: 'pending closure' stale-issue-label: 'pending closure'
stale-issue-message: > stale-issue-message: >

View File

@ -10,7 +10,7 @@ NetBox runs as a web application atop the [Django](https://www.djangoproject.com
Python framework with a [PostgreSQL](https://www.postgresql.org/) database. For a Python framework with a [PostgreSQL](https://www.postgresql.org/) database. For a
complete list of requirements, see `requirements.txt`. The code is available [on GitHub](https://github.com/netbox-community/netbox). complete list of requirements, see `requirements.txt`. The code is available [on GitHub](https://github.com/netbox-community/netbox).
The complete documentation for NetBox can be found at [Read the Docs](https://netbox.readthedocs.io/en/stable/). The complete documentation for NetBox can be found at [Read the Docs](https://netbox.readthedocs.io/en/stable/). A public demo instance is available at https://demo.netbox.dev.
### Discussion ### Discussion

View File

@ -515,6 +515,14 @@ The file path to the location where custom scripts will be kept. By default, thi
--- ---
## SESSION_COOKIE_NAME
Default: `sessionid`
The name used for the session cookie. See the [Django documentation](https://docs.djangoproject.com/en/stable/ref/settings/#session-cookie-name) for more detail.
---
## SESSION_FILE_PATH ## SESSION_FILE_PATH
Default: None Default: None

View File

@ -1,5 +1,24 @@
# NetBox v2.11 # NetBox v2.11
## v2.11.3 (FUTURE)
### Enhancements
* [#6197](https://github.com/netbox-community/netbox/issues/6197) - Introduced `SESSION_COOKIE_NAME` config parameter
* [#6318](https://github.com/netbox-community/netbox/issues/6318) - Add OM5 MMF cable type
### Bug Fixes
* [#6240](https://github.com/netbox-community/netbox/issues/6240) - Fix display of available VLAN ranges under VLAN group view
* [#6308](https://github.com/netbox-community/netbox/issues/6308) - Fix linking of available VLANs in VLAN group view
* [#6309](https://github.com/netbox-community/netbox/issues/6309) - Restrict parent VM interface assignment to the parent VM
* [#6313](https://github.com/netbox-community/netbox/issues/6313) - Fix device type instance count under manufacturer view
* [#6321](https://github.com/netbox-community/netbox/issues/6321) - Restore "add an IP" button under prefix IPs view
* [#6333](https://github.com/netbox-community/netbox/issues/6333) - Fix filtering of circuit terminations by primary key
* [#6339](https://github.com/netbox-community/netbox/issues/6339) - Improve ordering of interfaces when viewing virtual chassis master
---
## v2.11.2 (2021-04-27) ## v2.11.2 (2021-04-27)
### Enhancements ### Enhancements

View File

@ -1,6 +1,6 @@
from rest_framework.routers import APIRootView from rest_framework.routers import APIRootView
from circuits import filters from circuits import filtersets
from circuits.models import * from circuits.models import *
from dcim.api.views import PassThroughPortMixin from dcim.api.views import PassThroughPortMixin
from extras.api.views import CustomFieldModelViewSet from extras.api.views import CustomFieldModelViewSet
@ -26,7 +26,7 @@ class ProviderViewSet(CustomFieldModelViewSet):
circuit_count=count_related(Circuit, 'provider') circuit_count=count_related(Circuit, 'provider')
) )
serializer_class = serializers.ProviderSerializer serializer_class = serializers.ProviderSerializer
filterset_class = filters.ProviderFilterSet filterset_class = filtersets.ProviderFilterSet
# #
@ -38,7 +38,7 @@ class CircuitTypeViewSet(CustomFieldModelViewSet):
circuit_count=count_related(Circuit, 'type') circuit_count=count_related(Circuit, 'type')
) )
serializer_class = serializers.CircuitTypeSerializer serializer_class = serializers.CircuitTypeSerializer
filterset_class = filters.CircuitTypeFilterSet filterset_class = filtersets.CircuitTypeFilterSet
# #
@ -50,7 +50,7 @@ class CircuitViewSet(CustomFieldModelViewSet):
'type', 'tenant', 'provider', 'termination_a', 'termination_z' 'type', 'tenant', 'provider', 'termination_a', 'termination_z'
).prefetch_related('tags') ).prefetch_related('tags')
serializer_class = serializers.CircuitSerializer serializer_class = serializers.CircuitSerializer
filterset_class = filters.CircuitFilterSet filterset_class = filtersets.CircuitFilterSet
# #
@ -62,7 +62,7 @@ class CircuitTerminationViewSet(PassThroughPortMixin, ModelViewSet):
'circuit', 'site', 'provider_network', 'cable' 'circuit', 'site', 'provider_network', 'cable'
) )
serializer_class = serializers.CircuitTerminationSerializer serializer_class = serializers.CircuitTerminationSerializer
filterset_class = filters.CircuitTerminationFilterSet filterset_class = filtersets.CircuitTerminationFilterSet
brief_prefetch_fields = ['circuit'] brief_prefetch_fields = ['circuit']
@ -73,4 +73,4 @@ class CircuitTerminationViewSet(PassThroughPortMixin, ModelViewSet):
class ProviderNetworkViewSet(CustomFieldModelViewSet): class ProviderNetworkViewSet(CustomFieldModelViewSet):
queryset = ProviderNetwork.objects.prefetch_related('tags') queryset = ProviderNetwork.objects.prefetch_related('tags')
serializer_class = serializers.ProviderNetworkSerializer serializer_class = serializers.ProviderNetworkSerializer
filterset_class = filters.ProviderNetworkFilterSet filterset_class = filtersets.ProviderNetworkFilterSet

View File

@ -1,13 +1,12 @@
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from dcim.filters import CableTerminationFilterSet from dcim.filtersets import CableTerminationFilterSet
from dcim.models import Region, Site, SiteGroup from dcim.models import Region, Site, SiteGroup
from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from extras.filters import TagFilter
from tenancy.filters import TenancyFilterSet from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet
from utilities.filters import ( from tenancy.filtersets import TenancyFilterSet
BaseFilterSet, NameSlugSearchFilterSet, TagFilter, TreeNodeMultipleChoiceFilter from utilities.filters import TreeNodeMultipleChoiceFilter
)
from .choices import * from .choices import *
from .models import * from .models import *
@ -20,7 +19,7 @@ __all__ = (
) )
class ProviderFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class ProviderFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -80,7 +79,7 @@ class ProviderFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdated
) )
class ProviderNetworkFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class ProviderNetworkFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -110,14 +109,14 @@ class ProviderNetworkFilterSet(BaseFilterSet, CustomFieldModelFilterSet, Created
).distinct() ).distinct()
class CircuitTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class CircuitTypeFilterSet(OrganizationalModelFilterSet):
class Meta: class Meta:
model = CircuitType model = CircuitType
fields = ['id', 'name', 'slug'] fields = ['id', 'name', 'slug']
class CircuitFilterSet(BaseFilterSet, CustomFieldModelFilterSet, TenancyFilterSet, CreatedUpdatedFilterSet): class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -207,7 +206,7 @@ class CircuitFilterSet(BaseFilterSet, CustomFieldModelFilterSet, TenancyFilterSe
).distinct() ).distinct()
class CircuitTerminationFilterSet(BaseFilterSet, CreatedUpdatedFilterSet, CableTerminationFilterSet): class CircuitTerminationFilterSet(ChangeLoggedModelFilterSet, CableTerminationFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -233,7 +232,7 @@ class CircuitTerminationFilterSet(BaseFilterSet, CreatedUpdatedFilterSet, CableT
class Meta: class Meta:
model = CircuitTermination model = CircuitTermination
fields = ['term_side', 'port_speed', 'upstream_speed', 'xconnect_id'] fields = ['id', 'term_side', 'port_speed', 'upstream_speed', 'xconnect_id']
def search(self, queryset, name, value): def search(self, queryset, name, value):
if not value.strip(): if not value.strip():

View File

@ -1,13 +1,14 @@
from django.test import TestCase from django.test import TestCase
from circuits.choices import * from circuits.choices import *
from circuits.filters import * from circuits.filtersets import *
from circuits.models import * from circuits.models import *
from dcim.models import Cable, Region, Site, SiteGroup from dcim.models import Cable, Region, Site, SiteGroup
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from utilities.testing import ChangeLoggedFilterSetTests
class ProviderTestCase(TestCase): class ProviderTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Provider.objects.all() queryset = Provider.objects.all()
filterset = ProviderFilterSet filterset = ProviderFilterSet
@ -61,10 +62,6 @@ class ProviderTestCase(TestCase):
CircuitTermination(circuit=circuits[1], site=sites[0], term_side='A'), CircuitTermination(circuit=circuits[1], site=sites[0], term_side='A'),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Provider 1', 'Provider 2']} params = {'name': ['Provider 1', 'Provider 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -103,7 +100,7 @@ class ProviderTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class CircuitTypeTestCase(TestCase): class CircuitTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = CircuitType.objects.all() queryset = CircuitType.objects.all()
filterset = CircuitTypeFilterSet filterset = CircuitTypeFilterSet
@ -116,10 +113,6 @@ class CircuitTypeTestCase(TestCase):
CircuitType(name='Circuit Type 3', slug='circuit-type-3'), CircuitType(name='Circuit Type 3', slug='circuit-type-3'),
)) ))
def test_id(self):
params = {'id': [self.queryset.first().pk]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_name(self): def test_name(self):
params = {'name': ['Circuit Type 1']} params = {'name': ['Circuit Type 1']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
@ -129,7 +122,7 @@ class CircuitTypeTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class CircuitTestCase(TestCase): class CircuitTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Circuit.objects.all() queryset = Circuit.objects.all()
filterset = CircuitFilterSet filterset = CircuitFilterSet
@ -213,10 +206,6 @@ class CircuitTestCase(TestCase):
)) ))
CircuitTermination.objects.bulk_create(circuit_terminations) CircuitTermination.objects.bulk_create(circuit_terminations)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_cid(self): def test_cid(self):
params = {'cid': ['Test Circuit 1', 'Test Circuit 2']} params = {'cid': ['Test Circuit 1', 'Test Circuit 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -288,7 +277,7 @@ class CircuitTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
class CircuitTerminationTestCase(TestCase): class CircuitTerminationTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = CircuitTermination.objects.all() queryset = CircuitTermination.objects.all()
filterset = CircuitTerminationFilterSet filterset = CircuitTerminationFilterSet
@ -382,7 +371,7 @@ class CircuitTerminationTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ProviderNetworkTestCase(TestCase): class ProviderNetworkTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = ProviderNetwork.objects.all() queryset = ProviderNetwork.objects.all()
filterset = ProviderNetworkFilterSet filterset = ProviderNetworkFilterSet
@ -403,10 +392,6 @@ class ProviderNetworkTestCase(TestCase):
) )
ProviderNetwork.objects.bulk_create(provider_networks) ProviderNetwork.objects.bulk_create(provider_networks)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Provider Network 1', 'Provider Network 2']} params = {'name': ['Provider Network 1', 'Provider Network 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -7,7 +7,7 @@ from netbox.views import generic
from utilities.forms import ConfirmationForm from utilities.forms import ConfirmationForm
from utilities.tables import paginate_table from utilities.tables import paginate_table
from utilities.utils import count_related from utilities.utils import count_related
from . import filters, forms, tables from . import filtersets, forms, tables
from .choices import CircuitTerminationSideChoices from .choices import CircuitTerminationSideChoices
from .models import * from .models import *
@ -20,7 +20,7 @@ class ProviderListView(generic.ObjectListView):
queryset = Provider.objects.annotate( queryset = Provider.objects.annotate(
count_circuits=count_related(Circuit, 'provider') count_circuits=count_related(Circuit, 'provider')
) )
filterset = filters.ProviderFilterSet filterset = filtersets.ProviderFilterSet
filterset_form = forms.ProviderFilterForm filterset_form = forms.ProviderFilterForm
table = tables.ProviderTable table = tables.ProviderTable
@ -63,7 +63,7 @@ class ProviderBulkEditView(generic.BulkEditView):
queryset = Provider.objects.annotate( queryset = Provider.objects.annotate(
count_circuits=count_related(Circuit, 'provider') count_circuits=count_related(Circuit, 'provider')
) )
filterset = filters.ProviderFilterSet filterset = filtersets.ProviderFilterSet
table = tables.ProviderTable table = tables.ProviderTable
form = forms.ProviderBulkEditForm form = forms.ProviderBulkEditForm
@ -72,7 +72,7 @@ class ProviderBulkDeleteView(generic.BulkDeleteView):
queryset = Provider.objects.annotate( queryset = Provider.objects.annotate(
count_circuits=count_related(Circuit, 'provider') count_circuits=count_related(Circuit, 'provider')
) )
filterset = filters.ProviderFilterSet filterset = filtersets.ProviderFilterSet
table = tables.ProviderTable table = tables.ProviderTable
@ -82,7 +82,7 @@ class ProviderBulkDeleteView(generic.BulkDeleteView):
class ProviderNetworkListView(generic.ObjectListView): class ProviderNetworkListView(generic.ObjectListView):
queryset = ProviderNetwork.objects.all() queryset = ProviderNetwork.objects.all()
filterset = filters.ProviderNetworkFilterSet filterset = filtersets.ProviderNetworkFilterSet
filterset_form = forms.ProviderNetworkFilterForm filterset_form = forms.ProviderNetworkFilterForm
table = tables.ProviderNetworkTable table = tables.ProviderNetworkTable
@ -125,14 +125,14 @@ class ProviderNetworkBulkImportView(generic.BulkImportView):
class ProviderNetworkBulkEditView(generic.BulkEditView): class ProviderNetworkBulkEditView(generic.BulkEditView):
queryset = ProviderNetwork.objects.all() queryset = ProviderNetwork.objects.all()
filterset = filters.ProviderNetworkFilterSet filterset = filtersets.ProviderNetworkFilterSet
table = tables.ProviderNetworkTable table = tables.ProviderNetworkTable
form = forms.ProviderNetworkBulkEditForm form = forms.ProviderNetworkBulkEditForm
class ProviderNetworkBulkDeleteView(generic.BulkDeleteView): class ProviderNetworkBulkDeleteView(generic.BulkDeleteView):
queryset = ProviderNetwork.objects.all() queryset = ProviderNetwork.objects.all()
filterset = filters.ProviderNetworkFilterSet filterset = filtersets.ProviderNetworkFilterSet
table = tables.ProviderNetworkTable table = tables.ProviderNetworkTable
@ -183,7 +183,7 @@ class CircuitTypeBulkEditView(generic.BulkEditView):
queryset = CircuitType.objects.annotate( queryset = CircuitType.objects.annotate(
circuit_count=count_related(Circuit, 'type') circuit_count=count_related(Circuit, 'type')
) )
filterset = filters.CircuitTypeFilterSet filterset = filtersets.CircuitTypeFilterSet
table = tables.CircuitTypeTable table = tables.CircuitTypeTable
form = forms.CircuitTypeBulkEditForm form = forms.CircuitTypeBulkEditForm
@ -203,7 +203,7 @@ class CircuitListView(generic.ObjectListView):
queryset = Circuit.objects.prefetch_related( queryset = Circuit.objects.prefetch_related(
'provider', 'type', 'tenant', 'termination_a', 'termination_z' 'provider', 'type', 'tenant', 'termination_a', 'termination_z'
) )
filterset = filters.CircuitFilterSet filterset = filtersets.CircuitFilterSet
filterset_form = forms.CircuitFilterForm filterset_form = forms.CircuitFilterForm
table = tables.CircuitTable table = tables.CircuitTable
@ -252,7 +252,7 @@ class CircuitBulkEditView(generic.BulkEditView):
queryset = Circuit.objects.prefetch_related( queryset = Circuit.objects.prefetch_related(
'provider', 'type', 'tenant', 'terminations' 'provider', 'type', 'tenant', 'terminations'
) )
filterset = filters.CircuitFilterSet filterset = filtersets.CircuitFilterSet
table = tables.CircuitTable table = tables.CircuitTable
form = forms.CircuitBulkEditForm form = forms.CircuitBulkEditForm
@ -261,7 +261,7 @@ class CircuitBulkDeleteView(generic.BulkDeleteView):
queryset = Circuit.objects.prefetch_related( queryset = Circuit.objects.prefetch_related(
'provider', 'type', 'tenant', 'terminations' 'provider', 'type', 'tenant', 'terminations'
) )
filterset = filters.CircuitFilterSet filterset = filtersets.CircuitFilterSet
table = tables.CircuitTable table = tables.CircuitTable

View File

@ -16,7 +16,7 @@ from rest_framework.routers import APIRootView
from rest_framework.viewsets import GenericViewSet, ViewSet from rest_framework.viewsets import GenericViewSet, ViewSet
from circuits.models import Circuit from circuits.models import Circuit
from dcim import filters from dcim import filtersets
from dcim.models import * from dcim.models import *
from extras.api.views import ConfigContextQuerySetMixin, CustomFieldModelViewSet from extras.api.views import ConfigContextQuerySetMixin, CustomFieldModelViewSet
from ipam.models import Prefix, VLAN from ipam.models import Prefix, VLAN
@ -103,7 +103,7 @@ class RegionViewSet(CustomFieldModelViewSet):
cumulative=True cumulative=True
) )
serializer_class = serializers.RegionSerializer serializer_class = serializers.RegionSerializer
filterset_class = filters.RegionFilterSet filterset_class = filtersets.RegionFilterSet
# #
@ -119,7 +119,7 @@ class SiteGroupViewSet(CustomFieldModelViewSet):
cumulative=True cumulative=True
) )
serializer_class = serializers.SiteGroupSerializer serializer_class = serializers.SiteGroupSerializer
filterset_class = filters.SiteGroupFilterSet filterset_class = filtersets.SiteGroupFilterSet
# #
@ -138,7 +138,7 @@ class SiteViewSet(CustomFieldModelViewSet):
virtualmachine_count=count_related(VirtualMachine, 'cluster__site') virtualmachine_count=count_related(VirtualMachine, 'cluster__site')
) )
serializer_class = serializers.SiteSerializer serializer_class = serializers.SiteSerializer
filterset_class = filters.SiteFilterSet filterset_class = filtersets.SiteFilterSet
# #
@ -160,7 +160,7 @@ class LocationViewSet(CustomFieldModelViewSet):
cumulative=True cumulative=True
).prefetch_related('site') ).prefetch_related('site')
serializer_class = serializers.LocationSerializer serializer_class = serializers.LocationSerializer
filterset_class = filters.LocationFilterSet filterset_class = filtersets.LocationFilterSet
# #
@ -172,7 +172,7 @@ class RackRoleViewSet(CustomFieldModelViewSet):
rack_count=count_related(Rack, 'role') rack_count=count_related(Rack, 'role')
) )
serializer_class = serializers.RackRoleSerializer serializer_class = serializers.RackRoleSerializer
filterset_class = filters.RackRoleFilterSet filterset_class = filtersets.RackRoleFilterSet
# #
@ -187,7 +187,7 @@ class RackViewSet(CustomFieldModelViewSet):
powerfeed_count=count_related(PowerFeed, 'rack') powerfeed_count=count_related(PowerFeed, 'rack')
) )
serializer_class = serializers.RackSerializer serializer_class = serializers.RackSerializer
filterset_class = filters.RackFilterSet filterset_class = filtersets.RackFilterSet
@swagger_auto_schema( @swagger_auto_schema(
responses={200: serializers.RackUnitSerializer(many=True)}, responses={200: serializers.RackUnitSerializer(many=True)},
@ -244,7 +244,7 @@ class RackViewSet(CustomFieldModelViewSet):
class RackReservationViewSet(ModelViewSet): class RackReservationViewSet(ModelViewSet):
queryset = RackReservation.objects.prefetch_related('rack', 'user', 'tenant') queryset = RackReservation.objects.prefetch_related('rack', 'user', 'tenant')
serializer_class = serializers.RackReservationSerializer serializer_class = serializers.RackReservationSerializer
filterset_class = filters.RackReservationFilterSet filterset_class = filtersets.RackReservationFilterSet
# Assign user from request # Assign user from request
def perform_create(self, serializer): def perform_create(self, serializer):
@ -262,7 +262,7 @@ class ManufacturerViewSet(CustomFieldModelViewSet):
platform_count=count_related(Platform, 'manufacturer') platform_count=count_related(Platform, 'manufacturer')
) )
serializer_class = serializers.ManufacturerSerializer serializer_class = serializers.ManufacturerSerializer
filterset_class = filters.ManufacturerFilterSet filterset_class = filtersets.ManufacturerFilterSet
# #
@ -274,7 +274,7 @@ class DeviceTypeViewSet(CustomFieldModelViewSet):
device_count=count_related(Device, 'device_type') device_count=count_related(Device, 'device_type')
) )
serializer_class = serializers.DeviceTypeSerializer serializer_class = serializers.DeviceTypeSerializer
filterset_class = filters.DeviceTypeFilterSet filterset_class = filtersets.DeviceTypeFilterSet
brief_prefetch_fields = ['manufacturer'] brief_prefetch_fields = ['manufacturer']
@ -285,49 +285,49 @@ class DeviceTypeViewSet(CustomFieldModelViewSet):
class ConsolePortTemplateViewSet(ModelViewSet): class ConsolePortTemplateViewSet(ModelViewSet):
queryset = ConsolePortTemplate.objects.prefetch_related('device_type__manufacturer') queryset = ConsolePortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.ConsolePortTemplateSerializer serializer_class = serializers.ConsolePortTemplateSerializer
filterset_class = filters.ConsolePortTemplateFilterSet filterset_class = filtersets.ConsolePortTemplateFilterSet
class ConsoleServerPortTemplateViewSet(ModelViewSet): class ConsoleServerPortTemplateViewSet(ModelViewSet):
queryset = ConsoleServerPortTemplate.objects.prefetch_related('device_type__manufacturer') queryset = ConsoleServerPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.ConsoleServerPortTemplateSerializer serializer_class = serializers.ConsoleServerPortTemplateSerializer
filterset_class = filters.ConsoleServerPortTemplateFilterSet filterset_class = filtersets.ConsoleServerPortTemplateFilterSet
class PowerPortTemplateViewSet(ModelViewSet): class PowerPortTemplateViewSet(ModelViewSet):
queryset = PowerPortTemplate.objects.prefetch_related('device_type__manufacturer') queryset = PowerPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.PowerPortTemplateSerializer serializer_class = serializers.PowerPortTemplateSerializer
filterset_class = filters.PowerPortTemplateFilterSet filterset_class = filtersets.PowerPortTemplateFilterSet
class PowerOutletTemplateViewSet(ModelViewSet): class PowerOutletTemplateViewSet(ModelViewSet):
queryset = PowerOutletTemplate.objects.prefetch_related('device_type__manufacturer') queryset = PowerOutletTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.PowerOutletTemplateSerializer serializer_class = serializers.PowerOutletTemplateSerializer
filterset_class = filters.PowerOutletTemplateFilterSet filterset_class = filtersets.PowerOutletTemplateFilterSet
class InterfaceTemplateViewSet(ModelViewSet): class InterfaceTemplateViewSet(ModelViewSet):
queryset = InterfaceTemplate.objects.prefetch_related('device_type__manufacturer') queryset = InterfaceTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.InterfaceTemplateSerializer serializer_class = serializers.InterfaceTemplateSerializer
filterset_class = filters.InterfaceTemplateFilterSet filterset_class = filtersets.InterfaceTemplateFilterSet
class FrontPortTemplateViewSet(ModelViewSet): class FrontPortTemplateViewSet(ModelViewSet):
queryset = FrontPortTemplate.objects.prefetch_related('device_type__manufacturer') queryset = FrontPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.FrontPortTemplateSerializer serializer_class = serializers.FrontPortTemplateSerializer
filterset_class = filters.FrontPortTemplateFilterSet filterset_class = filtersets.FrontPortTemplateFilterSet
class RearPortTemplateViewSet(ModelViewSet): class RearPortTemplateViewSet(ModelViewSet):
queryset = RearPortTemplate.objects.prefetch_related('device_type__manufacturer') queryset = RearPortTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.RearPortTemplateSerializer serializer_class = serializers.RearPortTemplateSerializer
filterset_class = filters.RearPortTemplateFilterSet filterset_class = filtersets.RearPortTemplateFilterSet
class DeviceBayTemplateViewSet(ModelViewSet): class DeviceBayTemplateViewSet(ModelViewSet):
queryset = DeviceBayTemplate.objects.prefetch_related('device_type__manufacturer') queryset = DeviceBayTemplate.objects.prefetch_related('device_type__manufacturer')
serializer_class = serializers.DeviceBayTemplateSerializer serializer_class = serializers.DeviceBayTemplateSerializer
filterset_class = filters.DeviceBayTemplateFilterSet filterset_class = filtersets.DeviceBayTemplateFilterSet
# #
@ -340,7 +340,7 @@ class DeviceRoleViewSet(CustomFieldModelViewSet):
virtualmachine_count=count_related(VirtualMachine, 'role') virtualmachine_count=count_related(VirtualMachine, 'role')
) )
serializer_class = serializers.DeviceRoleSerializer serializer_class = serializers.DeviceRoleSerializer
filterset_class = filters.DeviceRoleFilterSet filterset_class = filtersets.DeviceRoleFilterSet
# #
@ -353,7 +353,7 @@ class PlatformViewSet(CustomFieldModelViewSet):
virtualmachine_count=count_related(VirtualMachine, 'platform') virtualmachine_count=count_related(VirtualMachine, 'platform')
) )
serializer_class = serializers.PlatformSerializer serializer_class = serializers.PlatformSerializer
filterset_class = filters.PlatformFilterSet filterset_class = filtersets.PlatformFilterSet
# #
@ -365,7 +365,7 @@ class DeviceViewSet(ConfigContextQuerySetMixin, CustomFieldModelViewSet):
'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'site', 'location', 'rack', 'parent_bay', 'device_type__manufacturer', 'device_role', 'tenant', 'platform', 'site', 'location', 'rack', 'parent_bay',
'virtual_chassis__master', 'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'tags', 'virtual_chassis__master', 'primary_ip4__nat_outside', 'primary_ip6__nat_outside', 'tags',
) )
filterset_class = filters.DeviceFilterSet filterset_class = filtersets.DeviceFilterSet
def get_serializer_class(self): def get_serializer_class(self):
""" """
@ -510,7 +510,7 @@ class DeviceViewSet(ConfigContextQuerySetMixin, CustomFieldModelViewSet):
class ConsolePortViewSet(PathEndpointMixin, ModelViewSet): class ConsolePortViewSet(PathEndpointMixin, ModelViewSet):
queryset = ConsolePort.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags') queryset = ConsolePort.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags')
serializer_class = serializers.ConsolePortSerializer serializer_class = serializers.ConsolePortSerializer
filterset_class = filters.ConsolePortFilterSet filterset_class = filtersets.ConsolePortFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
@ -519,21 +519,21 @@ class ConsoleServerPortViewSet(PathEndpointMixin, ModelViewSet):
'device', '_path__destination', 'cable', '_cable_peer', 'tags' 'device', '_path__destination', 'cable', '_cable_peer', 'tags'
) )
serializer_class = serializers.ConsoleServerPortSerializer serializer_class = serializers.ConsoleServerPortSerializer
filterset_class = filters.ConsoleServerPortFilterSet filterset_class = filtersets.ConsoleServerPortFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
class PowerPortViewSet(PathEndpointMixin, ModelViewSet): class PowerPortViewSet(PathEndpointMixin, ModelViewSet):
queryset = PowerPort.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags') queryset = PowerPort.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags')
serializer_class = serializers.PowerPortSerializer serializer_class = serializers.PowerPortSerializer
filterset_class = filters.PowerPortFilterSet filterset_class = filtersets.PowerPortFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
class PowerOutletViewSet(PathEndpointMixin, ModelViewSet): class PowerOutletViewSet(PathEndpointMixin, ModelViewSet):
queryset = PowerOutlet.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags') queryset = PowerOutlet.objects.prefetch_related('device', '_path__destination', 'cable', '_cable_peer', 'tags')
serializer_class = serializers.PowerOutletSerializer serializer_class = serializers.PowerOutletSerializer
filterset_class = filters.PowerOutletFilterSet filterset_class = filtersets.PowerOutletFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
@ -542,35 +542,35 @@ class InterfaceViewSet(PathEndpointMixin, ModelViewSet):
'device', 'parent', 'lag', '_path__destination', 'cable', '_cable_peer', 'ip_addresses', 'tags' 'device', 'parent', 'lag', '_path__destination', 'cable', '_cable_peer', 'ip_addresses', 'tags'
) )
serializer_class = serializers.InterfaceSerializer serializer_class = serializers.InterfaceSerializer
filterset_class = filters.InterfaceFilterSet filterset_class = filtersets.InterfaceFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
class FrontPortViewSet(PassThroughPortMixin, ModelViewSet): class FrontPortViewSet(PassThroughPortMixin, ModelViewSet):
queryset = FrontPort.objects.prefetch_related('device__device_type__manufacturer', 'rear_port', 'cable', 'tags') queryset = FrontPort.objects.prefetch_related('device__device_type__manufacturer', 'rear_port', 'cable', 'tags')
serializer_class = serializers.FrontPortSerializer serializer_class = serializers.FrontPortSerializer
filterset_class = filters.FrontPortFilterSet filterset_class = filtersets.FrontPortFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
class RearPortViewSet(PassThroughPortMixin, ModelViewSet): class RearPortViewSet(PassThroughPortMixin, ModelViewSet):
queryset = RearPort.objects.prefetch_related('device__device_type__manufacturer', 'cable', 'tags') queryset = RearPort.objects.prefetch_related('device__device_type__manufacturer', 'cable', 'tags')
serializer_class = serializers.RearPortSerializer serializer_class = serializers.RearPortSerializer
filterset_class = filters.RearPortFilterSet filterset_class = filtersets.RearPortFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
class DeviceBayViewSet(ModelViewSet): class DeviceBayViewSet(ModelViewSet):
queryset = DeviceBay.objects.prefetch_related('installed_device').prefetch_related('tags') queryset = DeviceBay.objects.prefetch_related('installed_device').prefetch_related('tags')
serializer_class = serializers.DeviceBaySerializer serializer_class = serializers.DeviceBaySerializer
filterset_class = filters.DeviceBayFilterSet filterset_class = filtersets.DeviceBayFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
class InventoryItemViewSet(ModelViewSet): class InventoryItemViewSet(ModelViewSet):
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer').prefetch_related('tags') queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer').prefetch_related('tags')
serializer_class = serializers.InventoryItemSerializer serializer_class = serializers.InventoryItemSerializer
filterset_class = filters.InventoryItemFilterSet filterset_class = filtersets.InventoryItemFilterSet
brief_prefetch_fields = ['device'] brief_prefetch_fields = ['device']
@ -583,7 +583,7 @@ class ConsoleConnectionViewSet(ListModelMixin, GenericViewSet):
_path__destination_id__isnull=False _path__destination_id__isnull=False
) )
serializer_class = serializers.ConsolePortSerializer serializer_class = serializers.ConsolePortSerializer
filterset_class = filters.ConsoleConnectionFilterSet filterset_class = filtersets.ConsoleConnectionFilterSet
class PowerConnectionViewSet(ListModelMixin, GenericViewSet): class PowerConnectionViewSet(ListModelMixin, GenericViewSet):
@ -591,7 +591,7 @@ class PowerConnectionViewSet(ListModelMixin, GenericViewSet):
_path__destination_id__isnull=False _path__destination_id__isnull=False
) )
serializer_class = serializers.PowerPortSerializer serializer_class = serializers.PowerPortSerializer
filterset_class = filters.PowerConnectionFilterSet filterset_class = filtersets.PowerConnectionFilterSet
class InterfaceConnectionViewSet(ListModelMixin, GenericViewSet): class InterfaceConnectionViewSet(ListModelMixin, GenericViewSet):
@ -603,7 +603,7 @@ class InterfaceConnectionViewSet(ListModelMixin, GenericViewSet):
pk__lt=F('_path__destination_id') pk__lt=F('_path__destination_id')
) )
serializer_class = serializers.InterfaceConnectionSerializer serializer_class = serializers.InterfaceConnectionSerializer
filterset_class = filters.InterfaceConnectionFilterSet filterset_class = filtersets.InterfaceConnectionFilterSet
# #
@ -616,7 +616,7 @@ class CableViewSet(ModelViewSet):
'termination_a', 'termination_b' 'termination_a', 'termination_b'
) )
serializer_class = serializers.CableSerializer serializer_class = serializers.CableSerializer
filterset_class = filters.CableFilterSet filterset_class = filtersets.CableFilterSet
# #
@ -628,7 +628,7 @@ class VirtualChassisViewSet(ModelViewSet):
member_count=count_related(Device, 'virtual_chassis') member_count=count_related(Device, 'virtual_chassis')
) )
serializer_class = serializers.VirtualChassisSerializer serializer_class = serializers.VirtualChassisSerializer
filterset_class = filters.VirtualChassisFilterSet filterset_class = filtersets.VirtualChassisFilterSet
brief_prefetch_fields = ['master'] brief_prefetch_fields = ['master']
@ -643,7 +643,7 @@ class PowerPanelViewSet(ModelViewSet):
powerfeed_count=count_related(PowerFeed, 'power_panel') powerfeed_count=count_related(PowerFeed, 'power_panel')
) )
serializer_class = serializers.PowerPanelSerializer serializer_class = serializers.PowerPanelSerializer
filterset_class = filters.PowerPanelFilterSet filterset_class = filtersets.PowerPanelFilterSet
# #
@ -655,7 +655,7 @@ class PowerFeedViewSet(PathEndpointMixin, CustomFieldModelViewSet):
'power_panel', 'rack', '_path__destination', 'cable', '_cable_peer', 'tags' 'power_panel', 'rack', '_path__destination', 'cable', '_cable_peer', 'tags'
) )
serializer_class = serializers.PowerFeedSerializer serializer_class = serializers.PowerFeedSerializer
filterset_class = filters.PowerFeedFilterSet filterset_class = filtersets.PowerFeedFilterSet
# #

View File

@ -1001,6 +1001,7 @@ class CableTypeChoices(ChoiceSet):
TYPE_MMF_OM2 = 'mmf-om2' TYPE_MMF_OM2 = 'mmf-om2'
TYPE_MMF_OM3 = 'mmf-om3' TYPE_MMF_OM3 = 'mmf-om3'
TYPE_MMF_OM4 = 'mmf-om4' TYPE_MMF_OM4 = 'mmf-om4'
TYPE_MMF_OM5 = 'mmf-om5'
TYPE_SMF = 'smf' TYPE_SMF = 'smf'
TYPE_SMF_OS1 = 'smf-os1' TYPE_SMF_OS1 = 'smf-os1'
TYPE_SMF_OS2 = 'smf-os2' TYPE_SMF_OS2 = 'smf-os2'
@ -1031,6 +1032,7 @@ class CableTypeChoices(ChoiceSet):
(TYPE_MMF_OM2, 'Multimode Fiber (OM2)'), (TYPE_MMF_OM2, 'Multimode Fiber (OM2)'),
(TYPE_MMF_OM3, 'Multimode Fiber (OM3)'), (TYPE_MMF_OM3, 'Multimode Fiber (OM3)'),
(TYPE_MMF_OM4, 'Multimode Fiber (OM4)'), (TYPE_MMF_OM4, 'Multimode Fiber (OM4)'),
(TYPE_MMF_OM5, 'Multimode Fiber (OM5)'),
(TYPE_SMF, 'Singlemode Fiber'), (TYPE_SMF, 'Singlemode Fiber'),
(TYPE_SMF_OS1, 'Singlemode Fiber (OS1)'), (TYPE_SMF_OS1, 'Singlemode Fiber (OS1)'),
(TYPE_SMF_OS2, 'Singlemode Fiber (OS2)'), (TYPE_SMF_OS2, 'Singlemode Fiber (OS2)'),

View File

@ -1,13 +1,16 @@
import django_filters import django_filters
from django.contrib.auth.models import User from django.contrib.auth.models import User
from extras.filters import CustomFieldModelFilterSet, LocalConfigContextFilterSet, CreatedUpdatedFilterSet from extras.filters import TagFilter
from tenancy.filters import TenancyFilterSet from extras.filtersets import LocalConfigContextFilterSet
from netbox.filtersets import (
BaseFilterSet, ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet,
)
from tenancy.filtersets import TenancyFilterSet
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.choices import ColorChoices from utilities.choices import ColorChoices
from utilities.filters import ( from utilities.filters import (
BaseFilterSet, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, TreeNodeMultipleChoiceFilter,
NameSlugSearchFilterSet, TagFilter, TreeNodeMultipleChoiceFilter,
) )
from virtualization.models import Cluster from virtualization.models import Cluster
from .choices import * from .choices import *
@ -57,7 +60,7 @@ __all__ = (
) )
class RegionFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class RegionFilterSet(OrganizationalModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
label='Parent region (ID)', label='Parent region (ID)',
@ -74,7 +77,7 @@ class RegionFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilt
fields = ['id', 'name', 'slug', 'description'] fields = ['id', 'name', 'slug', 'description']
class SiteGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class SiteGroupFilterSet(OrganizationalModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
label='Parent site group (ID)', label='Parent site group (ID)',
@ -91,7 +94,7 @@ class SiteGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedF
fields = ['id', 'name', 'slug', 'description'] fields = ['id', 'name', 'slug', 'description']
class SiteFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class SiteFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -154,7 +157,7 @@ class SiteFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet,
return queryset.filter(qs_filter) return queryset.filter(qs_filter)
class LocationFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class LocationFilterSet(OrganizationalModelFilterSet):
region_id = TreeNodeMultipleChoiceFilter( region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
@ -218,14 +221,14 @@ class LocationFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFi
) )
class RackRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class RackRoleFilterSet(OrganizationalModelFilterSet):
class Meta: class Meta:
model = RackRole model = RackRole
fields = ['id', 'name', 'slug', 'color'] fields = ['id', 'name', 'slug', 'color']
class RackFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class RackFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -323,7 +326,7 @@ class RackFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet,
) )
class RackReservationFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class RackReservationFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -383,14 +386,14 @@ class RackReservationFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModel
) )
class ManufacturerFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class ManufacturerFilterSet(OrganizationalModelFilterSet):
class Meta: class Meta:
model = Manufacturer model = Manufacturer
fields = ['id', 'name', 'slug', 'description'] fields = ['id', 'name', 'slug', 'description']
class DeviceTypeFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class DeviceTypeFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -476,7 +479,7 @@ class DeviceTypeFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdat
return queryset.exclude(devicebaytemplates__isnull=value) return queryset.exclude(devicebaytemplates__isnull=value)
class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class DeviceTypeComponentFilterSet(django_filters.FilterSet):
devicetype_id = django_filters.ModelMultipleChoiceFilter( devicetype_id = django_filters.ModelMultipleChoiceFilter(
queryset=DeviceType.objects.all(), queryset=DeviceType.objects.all(),
field_name='device_type_id', field_name='device_type_id',
@ -484,28 +487,28 @@ class DeviceTypeComponentFilterSet(NameSlugSearchFilterSet, CreatedUpdatedFilter
) )
class ConsolePortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): class ConsolePortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
class Meta: class Meta:
model = ConsolePortTemplate model = ConsolePortTemplate
fields = ['id', 'name', 'type'] fields = ['id', 'name', 'type']
class ConsoleServerPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): class ConsoleServerPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
class Meta: class Meta:
model = ConsoleServerPortTemplate model = ConsoleServerPortTemplate
fields = ['id', 'name', 'type'] fields = ['id', 'name', 'type']
class PowerPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): class PowerPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
class Meta: class Meta:
model = PowerPortTemplate model = PowerPortTemplate
fields = ['id', 'name', 'type', 'maximum_draw', 'allocated_draw'] fields = ['id', 'name', 'type', 'maximum_draw', 'allocated_draw']
class PowerOutletTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): class PowerOutletTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
feed_leg = django_filters.MultipleChoiceFilter( feed_leg = django_filters.MultipleChoiceFilter(
choices=PowerOutletFeedLegChoices, choices=PowerOutletFeedLegChoices,
null_value=None null_value=None
@ -516,7 +519,7 @@ class PowerOutletTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
fields = ['id', 'name', 'type', 'feed_leg'] fields = ['id', 'name', 'type', 'feed_leg']
class InterfaceTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): class InterfaceTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=InterfaceTypeChoices, choices=InterfaceTypeChoices,
null_value=None null_value=None
@ -527,7 +530,7 @@ class InterfaceTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
fields = ['id', 'name', 'type', 'mgmt_only'] fields = ['id', 'name', 'type', 'mgmt_only']
class FrontPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): class FrontPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PortTypeChoices, choices=PortTypeChoices,
null_value=None null_value=None
@ -538,7 +541,7 @@ class FrontPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
fields = ['id', 'name', 'type'] fields = ['id', 'name', 'type']
class RearPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): class RearPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PortTypeChoices, choices=PortTypeChoices,
null_value=None null_value=None
@ -549,21 +552,21 @@ class RearPortTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet):
fields = ['id', 'name', 'type', 'positions'] fields = ['id', 'name', 'type', 'positions']
class DeviceBayTemplateFilterSet(BaseFilterSet, DeviceTypeComponentFilterSet): class DeviceBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
class Meta: class Meta:
model = DeviceBayTemplate model = DeviceBayTemplate
fields = ['id', 'name'] fields = ['id', 'name']
class DeviceRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class DeviceRoleFilterSet(OrganizationalModelFilterSet):
class Meta: class Meta:
model = DeviceRole model = DeviceRole
fields = ['id', 'name', 'slug', 'color', 'vm_role'] fields = ['id', 'name', 'slug', 'color', 'vm_role']
class PlatformFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class PlatformFilterSet(OrganizationalModelFilterSet):
manufacturer_id = django_filters.ModelMultipleChoiceFilter( manufacturer_id = django_filters.ModelMultipleChoiceFilter(
field_name='manufacturer', field_name='manufacturer',
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@ -581,13 +584,7 @@ class PlatformFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFi
fields = ['id', 'name', 'slug', 'napalm_driver', 'description'] fields = ['id', 'name', 'slug', 'napalm_driver', 'description']
class DeviceFilterSet( class DeviceFilterSet(PrimaryModelFilterSet, TenancyFilterSet, LocalConfigContextFilterSet):
BaseFilterSet,
TenancyFilterSet,
LocalConfigContextFilterSet,
CustomFieldModelFilterSet,
CreatedUpdatedFilterSet
):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -792,7 +789,7 @@ class DeviceFilterSet(
return queryset.exclude(devicebays__isnull=value) return queryset.exclude(devicebays__isnull=value)
class DeviceComponentFilterSet(CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class DeviceComponentFilterSet(django_filters.FilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -876,7 +873,7 @@ class PathEndpointFilterSet(django_filters.FilterSet):
return queryset.filter(Q(_path__isnull=True) | Q(_path__is_active=False)) return queryset.filter(Q(_path__isnull=True) | Q(_path__is_active=False))
class ConsolePortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): class ConsolePortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=ConsolePortTypeChoices, choices=ConsolePortTypeChoices,
null_value=None null_value=None
@ -887,12 +884,7 @@ class ConsolePortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTermina
fields = ['id', 'name', 'label', 'description'] fields = ['id', 'name', 'label', 'description']
class ConsoleServerPortFilterSet( class ConsoleServerPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet):
BaseFilterSet,
DeviceComponentFilterSet,
CableTerminationFilterSet,
PathEndpointFilterSet
):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=ConsolePortTypeChoices, choices=ConsolePortTypeChoices,
null_value=None null_value=None
@ -903,7 +895,7 @@ class ConsoleServerPortFilterSet(
fields = ['id', 'name', 'label', 'description'] fields = ['id', 'name', 'label', 'description']
class PowerPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): class PowerPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PowerPortTypeChoices, choices=PowerPortTypeChoices,
null_value=None null_value=None
@ -914,7 +906,7 @@ class PowerPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminati
fields = ['id', 'name', 'label', 'maximum_draw', 'allocated_draw', 'description'] fields = ['id', 'name', 'label', 'maximum_draw', 'allocated_draw', 'description']
class PowerOutletFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): class PowerOutletFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PowerOutletTypeChoices, choices=PowerOutletTypeChoices,
null_value=None null_value=None
@ -929,7 +921,7 @@ class PowerOutletFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTermina
fields = ['id', 'name', 'label', 'feed_leg', 'description'] fields = ['id', 'name', 'label', 'feed_leg', 'description']
class InterfaceFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet): class InterfaceFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet, PathEndpointFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -1027,7 +1019,7 @@ class InterfaceFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminati
}.get(value, queryset.none()) }.get(value, queryset.none())
class FrontPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet): class FrontPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PortTypeChoices, choices=PortTypeChoices,
null_value=None null_value=None
@ -1038,7 +1030,7 @@ class FrontPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminati
fields = ['id', 'name', 'label', 'type', 'description'] fields = ['id', 'name', 'label', 'type', 'description']
class RearPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet): class RearPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PortTypeChoices, choices=PortTypeChoices,
null_value=None null_value=None
@ -1049,14 +1041,14 @@ class RearPortFilterSet(BaseFilterSet, DeviceComponentFilterSet, CableTerminatio
fields = ['id', 'name', 'label', 'type', 'positions', 'description'] fields = ['id', 'name', 'label', 'type', 'positions', 'description']
class DeviceBayFilterSet(BaseFilterSet, DeviceComponentFilterSet): class DeviceBayFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet):
class Meta: class Meta:
model = DeviceBay model = DeviceBay
fields = ['id', 'name', 'label', 'description'] fields = ['id', 'name', 'label', 'description']
class InventoryItemFilterSet(BaseFilterSet, DeviceComponentFilterSet): class InventoryItemFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -1129,7 +1121,7 @@ class InventoryItemFilterSet(BaseFilterSet, DeviceComponentFilterSet):
return queryset.filter(qs_filter) return queryset.filter(qs_filter)
class VirtualChassisFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class VirtualChassisFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -1209,7 +1201,7 @@ class VirtualChassisFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedU
return queryset.filter(qs_filter).distinct() return queryset.filter(qs_filter).distinct()
class CableFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class CableFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -1273,7 +1265,7 @@ class CableFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFil
return queryset return queryset
class ConnectionFilterSet: class ConnectionFilterSet(BaseFilterSet):
def filter_site(self, queryset, name, value): def filter_site(self, queryset, name, value):
if not value.strip(): if not value.strip():
@ -1286,7 +1278,7 @@ class ConnectionFilterSet:
return queryset.filter(**{f'{name}__in': value}) return queryset.filter(**{f'{name}__in': value})
class ConsoleConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): class ConsoleConnectionFilterSet(ConnectionFilterSet):
site = django_filters.CharFilter( site = django_filters.CharFilter(
method='filter_site', method='filter_site',
label='Site (slug)', label='Site (slug)',
@ -1304,7 +1296,7 @@ class ConsoleConnectionFilterSet(ConnectionFilterSet, BaseFilterSet):
fields = ['name'] fields = ['name']
class PowerConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): class PowerConnectionFilterSet(ConnectionFilterSet):
site = django_filters.CharFilter( site = django_filters.CharFilter(
method='filter_site', method='filter_site',
label='Site (slug)', label='Site (slug)',
@ -1322,7 +1314,7 @@ class PowerConnectionFilterSet(ConnectionFilterSet, BaseFilterSet):
fields = ['name'] fields = ['name']
class InterfaceConnectionFilterSet(ConnectionFilterSet, BaseFilterSet): class InterfaceConnectionFilterSet(ConnectionFilterSet):
site = django_filters.CharFilter( site = django_filters.CharFilter(
method='filter_site', method='filter_site',
label='Site (slug)', label='Site (slug)',
@ -1340,7 +1332,7 @@ class InterfaceConnectionFilterSet(ConnectionFilterSet, BaseFilterSet):
fields = [] fields = []
class PowerPanelFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class PowerPanelFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -1402,13 +1394,7 @@ class PowerPanelFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdat
return queryset.filter(qs_filter) return queryset.filter(qs_filter)
class PowerFeedFilterSet( class PowerFeedFilterSet(PrimaryModelFilterSet, CableTerminationFilterSet, PathEndpointFilterSet):
BaseFilterSet,
CableTerminationFilterSet,
PathEndpointFilterSet,
CustomFieldModelFilterSet,
CreatedUpdatedFilterSet
):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',

View File

@ -520,6 +520,7 @@ class DeviceInterfaceTable(InterfaceTable):
'description', 'mark_connected', 'cable', 'cable_color', 'cable_peer', 'connection', 'tags', 'ip_addresses', 'description', 'mark_connected', 'cable', 'cable_color', 'cable_peer', 'connection', 'tags', 'ip_addresses',
'untagged_vlan', 'tagged_vlans', 'actions', 'untagged_vlan', 'tagged_vlans', 'actions',
) )
order_by = ('name',)
default_columns = ( default_columns = (
'pk', 'name', 'label', 'enabled', 'type', 'parent', 'lag', 'mtu', 'mode', 'description', 'ip_addresses', 'pk', 'name', 'label', 'enabled', 'type', 'parent', 'lag', 'mtu', 'mode', 'description', 'ip_addresses',
'cable', 'connection', 'actions', 'cable', 'connection', 'actions',

View File

@ -2,14 +2,15 @@ from django.contrib.auth.models import User
from django.test import TestCase from django.test import TestCase
from dcim.choices import * from dcim.choices import *
from dcim.filters import * from dcim.filtersets import *
from dcim.models import * from dcim.models import *
from ipam.models import IPAddress from ipam.models import IPAddress
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from utilities.testing import ChangeLoggedFilterSetTests
from virtualization.models import Cluster, ClusterType from virtualization.models import Cluster, ClusterType
class RegionTestCase(TestCase): class RegionTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Region.objects.all() queryset = Region.objects.all()
filterset = RegionFilterSet filterset = RegionFilterSet
@ -35,10 +36,6 @@ class RegionTestCase(TestCase):
for region in child_regions: for region in child_regions:
region.save() region.save()
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Region 1', 'Region 2']} params = {'name': ['Region 1', 'Region 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -59,7 +56,7 @@ class RegionTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
class SiteGroupTestCase(TestCase): class SiteGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = SiteGroup.objects.all() queryset = SiteGroup.objects.all()
filterset = SiteGroupFilterSet filterset = SiteGroupFilterSet
@ -85,10 +82,6 @@ class SiteGroupTestCase(TestCase):
for sitegroup in child_sitegroups: for sitegroup in child_sitegroups:
sitegroup.save() sitegroup.save()
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Site Group 1', 'Site Group 2']} params = {'name': ['Site Group 1', 'Site Group 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -109,7 +102,7 @@ class SiteGroupTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
class SiteTestCase(TestCase): class SiteTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Site.objects.all() queryset = Site.objects.all()
filterset = SiteFilterSet filterset = SiteFilterSet
@ -154,10 +147,6 @@ class SiteTestCase(TestCase):
) )
Site.objects.bulk_create(sites) Site.objects.bulk_create(sites)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Site 1', 'Site 2']} params = {'name': ['Site 1', 'Site 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -227,7 +216,7 @@ class SiteTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class LocationTestCase(TestCase): class LocationTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Location.objects.all() queryset = Location.objects.all()
filterset = LocationFilterSet filterset = LocationFilterSet
@ -273,10 +262,6 @@ class LocationTestCase(TestCase):
for location in locations: for location in locations:
location.save() location.save()
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Location 1', 'Location 2']} params = {'name': ['Location 1', 'Location 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -318,7 +303,7 @@ class LocationTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class RackRoleTestCase(TestCase): class RackRoleTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = RackRole.objects.all() queryset = RackRole.objects.all()
filterset = RackRoleFilterSet filterset = RackRoleFilterSet
@ -332,10 +317,6 @@ class RackRoleTestCase(TestCase):
) )
RackRole.objects.bulk_create(rack_roles) RackRole.objects.bulk_create(rack_roles)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Rack Role 1', 'Rack Role 2']} params = {'name': ['Rack Role 1', 'Rack Role 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -349,7 +330,7 @@ class RackRoleTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class RackTestCase(TestCase): class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Rack.objects.all() queryset = Rack.objects.all()
filterset = RackFilterSet filterset = RackFilterSet
@ -416,10 +397,6 @@ class RackTestCase(TestCase):
) )
Rack.objects.bulk_create(racks) Rack.objects.bulk_create(racks)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Rack 1', 'Rack 2']} params = {'name': ['Rack 1', 'Rack 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -523,7 +500,7 @@ class RackTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class RackReservationTestCase(TestCase): class RackReservationTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = RackReservation.objects.all() queryset = RackReservation.objects.all()
filterset = RackReservationFilterSet filterset = RackReservationFilterSet
@ -581,10 +558,6 @@ class RackReservationTestCase(TestCase):
) )
RackReservation.objects.bulk_create(reservations) RackReservation.objects.bulk_create(reservations)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_site(self): def test_site(self):
sites = Site.objects.all()[:2] sites = Site.objects.all()[:2]
params = {'site_id': [sites[0].pk, sites[1].pk]} params = {'site_id': [sites[0].pk, sites[1].pk]}
@ -621,7 +594,7 @@ class RackReservationTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ManufacturerTestCase(TestCase): class ManufacturerTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Manufacturer.objects.all() queryset = Manufacturer.objects.all()
filterset = ManufacturerFilterSet filterset = ManufacturerFilterSet
@ -635,10 +608,6 @@ class ManufacturerTestCase(TestCase):
) )
Manufacturer.objects.bulk_create(manufacturers) Manufacturer.objects.bulk_create(manufacturers)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Manufacturer 1', 'Manufacturer 2']} params = {'name': ['Manufacturer 1', 'Manufacturer 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -652,7 +621,7 @@ class ManufacturerTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class DeviceTypeTestCase(TestCase): class DeviceTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = DeviceType.objects.all() queryset = DeviceType.objects.all()
filterset = DeviceTypeFilterSet filterset = DeviceTypeFilterSet
@ -708,10 +677,6 @@ class DeviceTypeTestCase(TestCase):
DeviceBayTemplate(device_type=device_types[1], name='Device Bay 2'), DeviceBayTemplate(device_type=device_types[1], name='Device Bay 2'),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_model(self): def test_model(self):
params = {'model': ['Model 1', 'Model 2']} params = {'model': ['Model 1', 'Model 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -788,7 +753,7 @@ class DeviceTypeTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class ConsolePortTemplateTestCase(TestCase): class ConsolePortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = ConsolePortTemplate.objects.all() queryset = ConsolePortTemplate.objects.all()
filterset = ConsolePortTemplateFilterSet filterset = ConsolePortTemplateFilterSet
@ -810,10 +775,6 @@ class ConsolePortTemplateTestCase(TestCase):
ConsolePortTemplate(device_type=device_types[2], name='Console Port 3'), ConsolePortTemplate(device_type=device_types[2], name='Console Port 3'),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Console Port 1', 'Console Port 2']} params = {'name': ['Console Port 1', 'Console Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -824,7 +785,7 @@ class ConsolePortTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ConsoleServerPortTemplateTestCase(TestCase): class ConsoleServerPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = ConsoleServerPortTemplate.objects.all() queryset = ConsoleServerPortTemplate.objects.all()
filterset = ConsoleServerPortTemplateFilterSet filterset = ConsoleServerPortTemplateFilterSet
@ -846,10 +807,6 @@ class ConsoleServerPortTemplateTestCase(TestCase):
ConsoleServerPortTemplate(device_type=device_types[2], name='Console Server Port 3'), ConsoleServerPortTemplate(device_type=device_types[2], name='Console Server Port 3'),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Console Server Port 1', 'Console Server Port 2']} params = {'name': ['Console Server Port 1', 'Console Server Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -860,7 +817,7 @@ class ConsoleServerPortTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class PowerPortTemplateTestCase(TestCase): class PowerPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = PowerPortTemplate.objects.all() queryset = PowerPortTemplate.objects.all()
filterset = PowerPortTemplateFilterSet filterset = PowerPortTemplateFilterSet
@ -882,10 +839,6 @@ class PowerPortTemplateTestCase(TestCase):
PowerPortTemplate(device_type=device_types[2], name='Power Port 3', maximum_draw=300, allocated_draw=150), PowerPortTemplate(device_type=device_types[2], name='Power Port 3', maximum_draw=300, allocated_draw=150),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Power Port 1', 'Power Port 2']} params = {'name': ['Power Port 1', 'Power Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -904,7 +857,7 @@ class PowerPortTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class PowerOutletTemplateTestCase(TestCase): class PowerOutletTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = PowerOutletTemplate.objects.all() queryset = PowerOutletTemplate.objects.all()
filterset = PowerOutletTemplateFilterSet filterset = PowerOutletTemplateFilterSet
@ -926,10 +879,6 @@ class PowerOutletTemplateTestCase(TestCase):
PowerOutletTemplate(device_type=device_types[2], name='Power Outlet 3', feed_leg=PowerOutletFeedLegChoices.FEED_LEG_C), PowerOutletTemplate(device_type=device_types[2], name='Power Outlet 3', feed_leg=PowerOutletFeedLegChoices.FEED_LEG_C),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Power Outlet 1', 'Power Outlet 2']} params = {'name': ['Power Outlet 1', 'Power Outlet 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -944,7 +893,7 @@ class PowerOutletTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class InterfaceTemplateTestCase(TestCase): class InterfaceTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = InterfaceTemplate.objects.all() queryset = InterfaceTemplate.objects.all()
filterset = InterfaceTemplateFilterSet filterset = InterfaceTemplateFilterSet
@ -966,10 +915,6 @@ class InterfaceTemplateTestCase(TestCase):
InterfaceTemplate(device_type=device_types[2], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_SFP, mgmt_only=False), InterfaceTemplate(device_type=device_types[2], name='Interface 3', type=InterfaceTypeChoices.TYPE_1GE_SFP, mgmt_only=False),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Interface 1', 'Interface 2']} params = {'name': ['Interface 1', 'Interface 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -990,7 +935,7 @@ class InterfaceTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class FrontPortTemplateTestCase(TestCase): class FrontPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = FrontPortTemplate.objects.all() queryset = FrontPortTemplate.objects.all()
filterset = FrontPortTemplateFilterSet filterset = FrontPortTemplateFilterSet
@ -1019,10 +964,6 @@ class FrontPortTemplateTestCase(TestCase):
FrontPortTemplate(device_type=device_types[2], name='Front Port 3', rear_port=rear_ports[2], type=PortTypeChoices.TYPE_BNC), FrontPortTemplate(device_type=device_types[2], name='Front Port 3', rear_port=rear_ports[2], type=PortTypeChoices.TYPE_BNC),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Front Port 1', 'Front Port 2']} params = {'name': ['Front Port 1', 'Front Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1037,7 +978,7 @@ class FrontPortTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class RearPortTemplateTestCase(TestCase): class RearPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = RearPortTemplate.objects.all() queryset = RearPortTemplate.objects.all()
filterset = RearPortTemplateFilterSet filterset = RearPortTemplateFilterSet
@ -1059,10 +1000,6 @@ class RearPortTemplateTestCase(TestCase):
RearPortTemplate(device_type=device_types[2], name='Rear Port 3', type=PortTypeChoices.TYPE_BNC, positions=3), RearPortTemplate(device_type=device_types[2], name='Rear Port 3', type=PortTypeChoices.TYPE_BNC, positions=3),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Rear Port 1', 'Rear Port 2']} params = {'name': ['Rear Port 1', 'Rear Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1081,7 +1018,7 @@ class RearPortTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class DeviceBayTemplateTestCase(TestCase): class DeviceBayTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = DeviceBayTemplate.objects.all() queryset = DeviceBayTemplate.objects.all()
filterset = DeviceBayTemplateFilterSet filterset = DeviceBayTemplateFilterSet
@ -1103,10 +1040,6 @@ class DeviceBayTemplateTestCase(TestCase):
DeviceBayTemplate(device_type=device_types[2], name='Device Bay 3'), DeviceBayTemplate(device_type=device_types[2], name='Device Bay 3'),
)) ))
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Device Bay 1', 'Device Bay 2']} params = {'name': ['Device Bay 1', 'Device Bay 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1117,7 +1050,7 @@ class DeviceBayTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class DeviceRoleTestCase(TestCase): class DeviceRoleTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = DeviceRole.objects.all() queryset = DeviceRole.objects.all()
filterset = DeviceRoleFilterSet filterset = DeviceRoleFilterSet
@ -1131,10 +1064,6 @@ class DeviceRoleTestCase(TestCase):
) )
DeviceRole.objects.bulk_create(device_roles) DeviceRole.objects.bulk_create(device_roles)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Device Role 1', 'Device Role 2']} params = {'name': ['Device Role 1', 'Device Role 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1154,7 +1083,7 @@ class DeviceRoleTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class PlatformTestCase(TestCase): class PlatformTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Platform.objects.all() queryset = Platform.objects.all()
filterset = PlatformFilterSet filterset = PlatformFilterSet
@ -1175,10 +1104,6 @@ class PlatformTestCase(TestCase):
) )
Platform.objects.bulk_create(platforms) Platform.objects.bulk_create(platforms)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Platform 1', 'Platform 2']} params = {'name': ['Platform 1', 'Platform 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1203,7 +1128,7 @@ class PlatformTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class DeviceTestCase(TestCase): class DeviceTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Device.objects.all() queryset = Device.objects.all()
filterset = DeviceFilterSet filterset = DeviceFilterSet
@ -1356,10 +1281,6 @@ class DeviceTestCase(TestCase):
Device.objects.filter(pk=devices[0].pk).update(virtual_chassis=virtual_chassis, vc_position=1, vc_priority=1) Device.objects.filter(pk=devices[0].pk).update(virtual_chassis=virtual_chassis, vc_position=1, vc_priority=1)
Device.objects.filter(pk=devices[1].pk).update(virtual_chassis=virtual_chassis, vc_position=2, vc_priority=2) Device.objects.filter(pk=devices[1].pk).update(virtual_chassis=virtual_chassis, vc_position=2, vc_priority=2)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Device 1', 'Device 2']} params = {'name': ['Device 1', 'Device 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1549,7 +1470,7 @@ class DeviceTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ConsolePortTestCase(TestCase): class ConsolePortTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = ConsolePort.objects.all() queryset = ConsolePort.objects.all()
filterset = ConsolePortFilterSet filterset = ConsolePortFilterSet
@ -1608,10 +1529,6 @@ class ConsolePortTestCase(TestCase):
Cable(termination_a=console_ports[1], termination_b=console_server_ports[1]).save() Cable(termination_a=console_ports[1], termination_b=console_server_ports[1]).save()
# Third port is not connected # Third port is not connected
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Console Port 1', 'Console Port 2']} params = {'name': ['Console Port 1', 'Console Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1665,7 +1582,7 @@ class ConsolePortTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class ConsoleServerPortTestCase(TestCase): class ConsoleServerPortTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = ConsoleServerPort.objects.all() queryset = ConsoleServerPort.objects.all()
filterset = ConsoleServerPortFilterSet filterset = ConsoleServerPortFilterSet
@ -1724,10 +1641,6 @@ class ConsoleServerPortTestCase(TestCase):
Cable(termination_a=console_server_ports[1], termination_b=console_ports[1]).save() Cable(termination_a=console_server_ports[1], termination_b=console_ports[1]).save()
# Third port is not connected # Third port is not connected
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Console Server Port 1', 'Console Server Port 2']} params = {'name': ['Console Server Port 1', 'Console Server Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1781,7 +1694,7 @@ class ConsoleServerPortTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class PowerPortTestCase(TestCase): class PowerPortTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = PowerPort.objects.all() queryset = PowerPort.objects.all()
filterset = PowerPortFilterSet filterset = PowerPortFilterSet
@ -1840,10 +1753,6 @@ class PowerPortTestCase(TestCase):
Cable(termination_a=power_ports[1], termination_b=power_outlets[1]).save() Cable(termination_a=power_ports[1], termination_b=power_outlets[1]).save()
# Third port is not connected # Third port is not connected
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Power Port 1', 'Power Port 2']} params = {'name': ['Power Port 1', 'Power Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1905,7 +1814,7 @@ class PowerPortTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class PowerOutletTestCase(TestCase): class PowerOutletTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = PowerOutlet.objects.all() queryset = PowerOutlet.objects.all()
filterset = PowerOutletFilterSet filterset = PowerOutletFilterSet
@ -1964,10 +1873,6 @@ class PowerOutletTestCase(TestCase):
Cable(termination_a=power_outlets[1], termination_b=power_ports[1]).save() Cable(termination_a=power_outlets[1], termination_b=power_ports[1]).save()
# Third port is not connected # Third port is not connected
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Power Outlet 1', 'Power Outlet 2']} params = {'name': ['Power Outlet 1', 'Power Outlet 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2025,7 +1930,7 @@ class PowerOutletTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class InterfaceTestCase(TestCase): class InterfaceTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Interface.objects.all() queryset = Interface.objects.all()
filterset = InterfaceFilterSet filterset = InterfaceFilterSet
@ -2081,10 +1986,6 @@ class InterfaceTestCase(TestCase):
Cable(termination_a=interfaces[1], termination_b=interfaces[4]).save() Cable(termination_a=interfaces[1], termination_b=interfaces[4]).save()
# Third pair is not connected # Third pair is not connected
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Interface 1', 'Interface 2']} params = {'name': ['Interface 1', 'Interface 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2200,7 +2101,7 @@ class InterfaceTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class FrontPortTestCase(TestCase): class FrontPortTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = FrontPort.objects.all() queryset = FrontPort.objects.all()
filterset = FrontPortFilterSet filterset = FrontPortFilterSet
@ -2266,10 +2167,6 @@ class FrontPortTestCase(TestCase):
Cable(termination_a=front_ports[1], termination_b=front_ports[4]).save() Cable(termination_a=front_ports[1], termination_b=front_ports[4]).save()
# Third port is not connected # Third port is not connected
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Front Port 1', 'Front Port 2']} params = {'name': ['Front Port 1', 'Front Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2321,7 +2218,7 @@ class FrontPortTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class RearPortTestCase(TestCase): class RearPortTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = RearPort.objects.all() queryset = RearPort.objects.all()
filterset = RearPortFilterSet filterset = RearPortFilterSet
@ -2377,10 +2274,6 @@ class RearPortTestCase(TestCase):
Cable(termination_a=rear_ports[1], termination_b=rear_ports[4]).save() Cable(termination_a=rear_ports[1], termination_b=rear_ports[4]).save()
# Third port is not connected # Third port is not connected
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Rear Port 1', 'Rear Port 2']} params = {'name': ['Rear Port 1', 'Rear Port 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2436,7 +2329,7 @@ class RearPortTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class DeviceBayTestCase(TestCase): class DeviceBayTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = DeviceBay.objects.all() queryset = DeviceBay.objects.all()
filterset = DeviceBayFilterSet filterset = DeviceBayFilterSet
@ -2483,10 +2376,6 @@ class DeviceBayTestCase(TestCase):
) )
DeviceBay.objects.bulk_create(device_bays) DeviceBay.objects.bulk_create(device_bays)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Device Bay 1', 'Device Bay 2']} params = {'name': ['Device Bay 1', 'Device Bay 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2528,7 +2417,7 @@ class DeviceBayTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class InventoryItemTestCase(TestCase): class InventoryItemTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = InventoryItem.objects.all() queryset = InventoryItem.objects.all()
filterset = InventoryItemFilterSet filterset = InventoryItemFilterSet
@ -2591,10 +2480,6 @@ class InventoryItemTestCase(TestCase):
for i in child_inventory_items: for i in child_inventory_items:
i.save() i.save()
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Inventory Item 1', 'Inventory Item 2']} params = {'name': ['Inventory Item 1', 'Inventory Item 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2666,7 +2551,7 @@ class InventoryItemTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class VirtualChassisTestCase(TestCase): class VirtualChassisTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VirtualChassis.objects.all() queryset = VirtualChassis.objects.all()
filterset = VirtualChassisFilterSet filterset = VirtualChassisFilterSet
@ -2721,10 +2606,6 @@ class VirtualChassisTestCase(TestCase):
Device.objects.filter(pk=devices[3].pk).update(virtual_chassis=virtual_chassis[1]) Device.objects.filter(pk=devices[3].pk).update(virtual_chassis=virtual_chassis[1])
Device.objects.filter(pk=devices[5].pk).update(virtual_chassis=virtual_chassis[2]) Device.objects.filter(pk=devices[5].pk).update(virtual_chassis=virtual_chassis[2])
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_domain(self): def test_domain(self):
params = {'domain': ['Domain 1', 'Domain 2']} params = {'domain': ['Domain 1', 'Domain 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2762,7 +2643,7 @@ class VirtualChassisTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class CableTestCase(TestCase): class CableTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Cable.objects.all() queryset = Cable.objects.all()
filterset = CableFilterSet filterset = CableFilterSet
@ -2827,10 +2708,6 @@ class CableTestCase(TestCase):
Cable(termination_a=interfaces[9], termination_b=interfaces[10], label='Cable 5', type=CableTypeChoices.TYPE_CAT6, status=CableStatusChoices.STATUS_PLANNED, color='e91e63', length=10, length_unit=CableLengthUnitChoices.UNIT_METER).save() Cable(termination_a=interfaces[9], termination_b=interfaces[10], label='Cable 5', type=CableTypeChoices.TYPE_CAT6, status=CableStatusChoices.STATUS_PLANNED, color='e91e63', length=10, length_unit=CableLengthUnitChoices.UNIT_METER).save()
Cable(termination_a=interfaces[11], termination_b=interfaces[0], label='Cable 6', type=CableTypeChoices.TYPE_CAT6, status=CableStatusChoices.STATUS_PLANNED, color='e91e63', length=20, length_unit=CableLengthUnitChoices.UNIT_METER).save() Cable(termination_a=interfaces[11], termination_b=interfaces[0], label='Cable 6', type=CableTypeChoices.TYPE_CAT6, status=CableStatusChoices.STATUS_PLANNED, color='e91e63', length=20, length_unit=CableLengthUnitChoices.UNIT_METER).save()
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_label(self): def test_label(self):
params = {'label': ['Cable 1', 'Cable 2']} params = {'label': ['Cable 1', 'Cable 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2886,7 +2763,7 @@ class CableTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
class PowerPanelTestCase(TestCase): class PowerPanelTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = PowerPanel.objects.all() queryset = PowerPanel.objects.all()
filterset = PowerPanelFilterSet filterset = PowerPanelFilterSet
@ -2931,10 +2808,6 @@ class PowerPanelTestCase(TestCase):
) )
PowerPanel.objects.bulk_create(power_panels) PowerPanel.objects.bulk_create(power_panels)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Power Panel 1', 'Power Panel 2']} params = {'name': ['Power Panel 1', 'Power Panel 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2966,7 +2839,7 @@ class PowerPanelTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class PowerFeedTestCase(TestCase): class PowerFeedTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = PowerFeed.objects.all() queryset = PowerFeed.objects.all()
filterset = PowerFeedFilterSet filterset = PowerFeedFilterSet
@ -3029,10 +2902,6 @@ class PowerFeedTestCase(TestCase):
Cable(termination_a=power_feeds[0], termination_b=power_ports[0]).save() Cable(termination_a=power_feeds[0], termination_b=power_ports[0]).save()
Cable(termination_a=power_feeds[1], termination_b=power_ports[1]).save() Cable(termination_a=power_feeds[1], termination_b=power_ports[1]).save()
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Power Feed 1', 'Power Feed 2']} params = {'name': ['Power Feed 1', 'Power Feed 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -24,7 +24,7 @@ from utilities.tables import paginate_table
from utilities.utils import csv_format, count_related from utilities.utils import csv_format, count_related
from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin from utilities.views import GetReturnURLMixin, ObjectPermissionRequiredMixin
from virtualization.models import VirtualMachine from virtualization.models import VirtualMachine
from . import filters, forms, tables from . import filtersets, forms, tables
from .choices import DeviceFaceChoices from .choices import DeviceFaceChoices
from .constants import NONCONNECTABLE_IFACE_TYPES from .constants import NONCONNECTABLE_IFACE_TYPES
from .models import ( from .models import (
@ -107,7 +107,7 @@ class RegionListView(generic.ObjectListView):
'site_count', 'site_count',
cumulative=True cumulative=True
) )
filterset = filters.RegionFilterSet filterset = filtersets.RegionFilterSet
filterset_form = forms.RegionFilterForm filterset_form = forms.RegionFilterForm
table = tables.RegionTable table = tables.RegionTable
@ -163,7 +163,7 @@ class RegionBulkEditView(generic.BulkEditView):
'site_count', 'site_count',
cumulative=True cumulative=True
) )
filterset = filters.RegionFilterSet filterset = filtersets.RegionFilterSet
table = tables.RegionTable table = tables.RegionTable
form = forms.RegionBulkEditForm form = forms.RegionBulkEditForm
@ -176,7 +176,7 @@ class RegionBulkDeleteView(generic.BulkDeleteView):
'site_count', 'site_count',
cumulative=True cumulative=True
) )
filterset = filters.RegionFilterSet filterset = filtersets.RegionFilterSet
table = tables.RegionTable table = tables.RegionTable
@ -192,7 +192,7 @@ class SiteGroupListView(generic.ObjectListView):
'site_count', 'site_count',
cumulative=True cumulative=True
) )
filterset = filters.SiteGroupFilterSet filterset = filtersets.SiteGroupFilterSet
filterset_form = forms.SiteGroupFilterForm filterset_form = forms.SiteGroupFilterForm
table = tables.SiteGroupTable table = tables.SiteGroupTable
@ -248,7 +248,7 @@ class SiteGroupBulkEditView(generic.BulkEditView):
'site_count', 'site_count',
cumulative=True cumulative=True
) )
filterset = filters.SiteGroupFilterSet filterset = filtersets.SiteGroupFilterSet
table = tables.SiteGroupTable table = tables.SiteGroupTable
form = forms.SiteGroupBulkEditForm form = forms.SiteGroupBulkEditForm
@ -261,7 +261,7 @@ class SiteGroupBulkDeleteView(generic.BulkDeleteView):
'site_count', 'site_count',
cumulative=True cumulative=True
) )
filterset = filters.SiteGroupFilterSet filterset = filtersets.SiteGroupFilterSet
table = tables.SiteGroupTable table = tables.SiteGroupTable
@ -271,7 +271,7 @@ class SiteGroupBulkDeleteView(generic.BulkDeleteView):
class SiteListView(generic.ObjectListView): class SiteListView(generic.ObjectListView):
queryset = Site.objects.all() queryset = Site.objects.all()
filterset = filters.SiteFilterSet filterset = filtersets.SiteFilterSet
filterset_form = forms.SiteFilterForm filterset_form = forms.SiteFilterForm
table = tables.SiteTable table = tables.SiteTable
@ -326,14 +326,14 @@ class SiteBulkImportView(generic.BulkImportView):
class SiteBulkEditView(generic.BulkEditView): class SiteBulkEditView(generic.BulkEditView):
queryset = Site.objects.prefetch_related('region', 'tenant') queryset = Site.objects.prefetch_related('region', 'tenant')
filterset = filters.SiteFilterSet filterset = filtersets.SiteFilterSet
table = tables.SiteTable table = tables.SiteTable
form = forms.SiteBulkEditForm form = forms.SiteBulkEditForm
class SiteBulkDeleteView(generic.BulkDeleteView): class SiteBulkDeleteView(generic.BulkDeleteView):
queryset = Site.objects.prefetch_related('region', 'tenant') queryset = Site.objects.prefetch_related('region', 'tenant')
filterset = filters.SiteFilterSet filterset = filtersets.SiteFilterSet
table = tables.SiteTable table = tables.SiteTable
@ -355,7 +355,7 @@ class LocationListView(generic.ObjectListView):
'rack_count', 'rack_count',
cumulative=True cumulative=True
) )
filterset = filters.LocationFilterSet filterset = filtersets.LocationFilterSet
filterset_form = forms.LocationFilterForm filterset_form = forms.LocationFilterForm
table = tables.LocationTable table = tables.LocationTable
@ -414,7 +414,7 @@ class LocationBulkEditView(generic.BulkEditView):
'rack_count', 'rack_count',
cumulative=True cumulative=True
).prefetch_related('site') ).prefetch_related('site')
filterset = filters.LocationFilterSet filterset = filtersets.LocationFilterSet
table = tables.LocationTable table = tables.LocationTable
form = forms.LocationBulkEditForm form = forms.LocationBulkEditForm
@ -427,7 +427,7 @@ class LocationBulkDeleteView(generic.BulkDeleteView):
'rack_count', 'rack_count',
cumulative=True cumulative=True
).prefetch_related('site') ).prefetch_related('site')
filterset = filters.LocationFilterSet filterset = filtersets.LocationFilterSet
table = tables.LocationTable table = tables.LocationTable
@ -478,7 +478,7 @@ class RackRoleBulkEditView(generic.BulkEditView):
queryset = RackRole.objects.annotate( queryset = RackRole.objects.annotate(
rack_count=count_related(Rack, 'role') rack_count=count_related(Rack, 'role')
) )
filterset = filters.RackRoleFilterSet filterset = filtersets.RackRoleFilterSet
table = tables.RackRoleTable table = tables.RackRoleTable
form = forms.RackRoleBulkEditForm form = forms.RackRoleBulkEditForm
@ -500,7 +500,7 @@ class RackListView(generic.ObjectListView):
).annotate( ).annotate(
device_count=count_related(Device, 'rack') device_count=count_related(Device, 'rack')
) )
filterset = filters.RackFilterSet filterset = filtersets.RackFilterSet
filterset_form = forms.RackFilterForm filterset_form = forms.RackFilterForm
table = tables.RackDetailTable table = tables.RackDetailTable
@ -513,7 +513,7 @@ class RackElevationListView(generic.ObjectListView):
def get(self, request): def get(self, request):
racks = filters.RackFilterSet(request.GET, self.queryset).qs racks = filtersets.RackFilterSet(request.GET, self.queryset).qs
total_count = racks.count() total_count = racks.count()
# Determine ordering # Determine ordering
@ -602,14 +602,14 @@ class RackBulkImportView(generic.BulkImportView):
class RackBulkEditView(generic.BulkEditView): class RackBulkEditView(generic.BulkEditView):
queryset = Rack.objects.prefetch_related('site', 'location', 'tenant', 'role') queryset = Rack.objects.prefetch_related('site', 'location', 'tenant', 'role')
filterset = filters.RackFilterSet filterset = filtersets.RackFilterSet
table = tables.RackTable table = tables.RackTable
form = forms.RackBulkEditForm form = forms.RackBulkEditForm
class RackBulkDeleteView(generic.BulkDeleteView): class RackBulkDeleteView(generic.BulkDeleteView):
queryset = Rack.objects.prefetch_related('site', 'location', 'tenant', 'role') queryset = Rack.objects.prefetch_related('site', 'location', 'tenant', 'role')
filterset = filters.RackFilterSet filterset = filtersets.RackFilterSet
table = tables.RackTable table = tables.RackTable
@ -619,7 +619,7 @@ class RackBulkDeleteView(generic.BulkDeleteView):
class RackReservationListView(generic.ObjectListView): class RackReservationListView(generic.ObjectListView):
queryset = RackReservation.objects.all() queryset = RackReservation.objects.all()
filterset = filters.RackReservationFilterSet filterset = filtersets.RackReservationFilterSet
filterset_form = forms.RackReservationFilterForm filterset_form = forms.RackReservationFilterForm
table = tables.RackReservationTable table = tables.RackReservationTable
@ -662,14 +662,14 @@ class RackReservationImportView(generic.BulkImportView):
class RackReservationBulkEditView(generic.BulkEditView): class RackReservationBulkEditView(generic.BulkEditView):
queryset = RackReservation.objects.prefetch_related('rack', 'user') queryset = RackReservation.objects.prefetch_related('rack', 'user')
filterset = filters.RackReservationFilterSet filterset = filtersets.RackReservationFilterSet
table = tables.RackReservationTable table = tables.RackReservationTable
form = forms.RackReservationBulkEditForm form = forms.RackReservationBulkEditForm
class RackReservationBulkDeleteView(generic.BulkDeleteView): class RackReservationBulkDeleteView(generic.BulkDeleteView):
queryset = RackReservation.objects.prefetch_related('rack', 'user') queryset = RackReservation.objects.prefetch_related('rack', 'user')
filterset = filters.RackReservationFilterSet filterset = filtersets.RackReservationFilterSet
table = tables.RackReservationTable table = tables.RackReservationTable
@ -692,6 +692,8 @@ class ManufacturerView(generic.ObjectView):
def get_extra_context(self, request, instance): def get_extra_context(self, request, instance):
devicetypes = DeviceType.objects.restrict(request.user, 'view').filter( devicetypes = DeviceType.objects.restrict(request.user, 'view').filter(
manufacturer=instance manufacturer=instance
).annotate(
instance_count=count_related(Device, 'device_type')
) )
devicetypes_table = tables.DeviceTypeTable(devicetypes) devicetypes_table = tables.DeviceTypeTable(devicetypes)
@ -722,7 +724,7 @@ class ManufacturerBulkEditView(generic.BulkEditView):
queryset = Manufacturer.objects.annotate( queryset = Manufacturer.objects.annotate(
devicetype_count=count_related(DeviceType, 'manufacturer') devicetype_count=count_related(DeviceType, 'manufacturer')
) )
filterset = filters.ManufacturerFilterSet filterset = filtersets.ManufacturerFilterSet
table = tables.ManufacturerTable table = tables.ManufacturerTable
form = forms.ManufacturerBulkEditForm form = forms.ManufacturerBulkEditForm
@ -742,7 +744,7 @@ class DeviceTypeListView(generic.ObjectListView):
queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(
instance_count=count_related(Device, 'device_type') instance_count=count_related(Device, 'device_type')
) )
filterset = filters.DeviceTypeFilterSet filterset = filtersets.DeviceTypeFilterSet
filterset_form = forms.DeviceTypeFilterForm filterset_form = forms.DeviceTypeFilterForm
table = tables.DeviceTypeTable table = tables.DeviceTypeTable
@ -848,7 +850,7 @@ class DeviceTypeBulkEditView(generic.BulkEditView):
queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(
instance_count=count_related(Device, 'device_type') instance_count=count_related(Device, 'device_type')
) )
filterset = filters.DeviceTypeFilterSet filterset = filtersets.DeviceTypeFilterSet
table = tables.DeviceTypeTable table = tables.DeviceTypeTable
form = forms.DeviceTypeBulkEditForm form = forms.DeviceTypeBulkEditForm
@ -857,7 +859,7 @@ class DeviceTypeBulkDeleteView(generic.BulkDeleteView):
queryset = DeviceType.objects.prefetch_related('manufacturer').annotate( queryset = DeviceType.objects.prefetch_related('manufacturer').annotate(
instance_count=count_related(Device, 'device_type') instance_count=count_related(Device, 'device_type')
) )
filterset = filters.DeviceTypeFilterSet filterset = filtersets.DeviceTypeFilterSet
table = tables.DeviceTypeTable table = tables.DeviceTypeTable
@ -1190,7 +1192,7 @@ class DeviceRoleBulkEditView(generic.BulkEditView):
device_count=count_related(Device, 'device_role'), device_count=count_related(Device, 'device_role'),
vm_count=count_related(VirtualMachine, 'role') vm_count=count_related(VirtualMachine, 'role')
) )
filterset = filters.DeviceRoleFilterSet filterset = filtersets.DeviceRoleFilterSet
table = tables.DeviceRoleTable table = tables.DeviceRoleTable
form = forms.DeviceRoleBulkEditForm form = forms.DeviceRoleBulkEditForm
@ -1249,7 +1251,7 @@ class PlatformBulkImportView(generic.BulkImportView):
class PlatformBulkEditView(generic.BulkEditView): class PlatformBulkEditView(generic.BulkEditView):
queryset = Platform.objects.all() queryset = Platform.objects.all()
filterset = filters.PlatformFilterSet filterset = filtersets.PlatformFilterSet
table = tables.PlatformTable table = tables.PlatformTable
form = forms.PlatformBulkEditForm form = forms.PlatformBulkEditForm
@ -1265,7 +1267,7 @@ class PlatformBulkDeleteView(generic.BulkDeleteView):
class DeviceListView(generic.ObjectListView): class DeviceListView(generic.ObjectListView):
queryset = Device.objects.all() queryset = Device.objects.all()
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
filterset_form = forms.DeviceFilterForm filterset_form = forms.DeviceFilterForm
table = tables.DeviceTable table = tables.DeviceTable
template_name = 'dcim/device_list.html' template_name = 'dcim/device_list.html'
@ -1600,14 +1602,14 @@ class ChildDeviceBulkImportView(generic.BulkImportView):
class DeviceBulkEditView(generic.BulkEditView): class DeviceBulkEditView(generic.BulkEditView):
queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer') queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer')
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
form = forms.DeviceBulkEditForm form = forms.DeviceBulkEditForm
class DeviceBulkDeleteView(generic.BulkDeleteView): class DeviceBulkDeleteView(generic.BulkDeleteView):
queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer') queryset = Device.objects.prefetch_related('tenant', 'site', 'rack', 'device_role', 'device_type__manufacturer')
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
@ -1617,7 +1619,7 @@ class DeviceBulkDeleteView(generic.BulkDeleteView):
class ConsolePortListView(generic.ObjectListView): class ConsolePortListView(generic.ObjectListView):
queryset = ConsolePort.objects.all() queryset = ConsolePort.objects.all()
filterset = filters.ConsolePortFilterSet filterset = filtersets.ConsolePortFilterSet
filterset_form = forms.ConsolePortFilterForm filterset_form = forms.ConsolePortFilterForm
table = tables.ConsolePortTable table = tables.ConsolePortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -1652,7 +1654,7 @@ class ConsolePortBulkImportView(generic.BulkImportView):
class ConsolePortBulkEditView(generic.BulkEditView): class ConsolePortBulkEditView(generic.BulkEditView):
queryset = ConsolePort.objects.all() queryset = ConsolePort.objects.all()
filterset = filters.ConsolePortFilterSet filterset = filtersets.ConsolePortFilterSet
table = tables.ConsolePortTable table = tables.ConsolePortTable
form = forms.ConsolePortBulkEditForm form = forms.ConsolePortBulkEditForm
@ -1667,7 +1669,7 @@ class ConsolePortBulkDisconnectView(BulkDisconnectView):
class ConsolePortBulkDeleteView(generic.BulkDeleteView): class ConsolePortBulkDeleteView(generic.BulkDeleteView):
queryset = ConsolePort.objects.all() queryset = ConsolePort.objects.all()
filterset = filters.ConsolePortFilterSet filterset = filtersets.ConsolePortFilterSet
table = tables.ConsolePortTable table = tables.ConsolePortTable
@ -1677,7 +1679,7 @@ class ConsolePortBulkDeleteView(generic.BulkDeleteView):
class ConsoleServerPortListView(generic.ObjectListView): class ConsoleServerPortListView(generic.ObjectListView):
queryset = ConsoleServerPort.objects.all() queryset = ConsoleServerPort.objects.all()
filterset = filters.ConsoleServerPortFilterSet filterset = filtersets.ConsoleServerPortFilterSet
filterset_form = forms.ConsoleServerPortFilterForm filterset_form = forms.ConsoleServerPortFilterForm
table = tables.ConsoleServerPortTable table = tables.ConsoleServerPortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -1712,7 +1714,7 @@ class ConsoleServerPortBulkImportView(generic.BulkImportView):
class ConsoleServerPortBulkEditView(generic.BulkEditView): class ConsoleServerPortBulkEditView(generic.BulkEditView):
queryset = ConsoleServerPort.objects.all() queryset = ConsoleServerPort.objects.all()
filterset = filters.ConsoleServerPortFilterSet filterset = filtersets.ConsoleServerPortFilterSet
table = tables.ConsoleServerPortTable table = tables.ConsoleServerPortTable
form = forms.ConsoleServerPortBulkEditForm form = forms.ConsoleServerPortBulkEditForm
@ -1727,7 +1729,7 @@ class ConsoleServerPortBulkDisconnectView(BulkDisconnectView):
class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView): class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView):
queryset = ConsoleServerPort.objects.all() queryset = ConsoleServerPort.objects.all()
filterset = filters.ConsoleServerPortFilterSet filterset = filtersets.ConsoleServerPortFilterSet
table = tables.ConsoleServerPortTable table = tables.ConsoleServerPortTable
@ -1737,7 +1739,7 @@ class ConsoleServerPortBulkDeleteView(generic.BulkDeleteView):
class PowerPortListView(generic.ObjectListView): class PowerPortListView(generic.ObjectListView):
queryset = PowerPort.objects.all() queryset = PowerPort.objects.all()
filterset = filters.PowerPortFilterSet filterset = filtersets.PowerPortFilterSet
filterset_form = forms.PowerPortFilterForm filterset_form = forms.PowerPortFilterForm
table = tables.PowerPortTable table = tables.PowerPortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -1772,7 +1774,7 @@ class PowerPortBulkImportView(generic.BulkImportView):
class PowerPortBulkEditView(generic.BulkEditView): class PowerPortBulkEditView(generic.BulkEditView):
queryset = PowerPort.objects.all() queryset = PowerPort.objects.all()
filterset = filters.PowerPortFilterSet filterset = filtersets.PowerPortFilterSet
table = tables.PowerPortTable table = tables.PowerPortTable
form = forms.PowerPortBulkEditForm form = forms.PowerPortBulkEditForm
@ -1787,7 +1789,7 @@ class PowerPortBulkDisconnectView(BulkDisconnectView):
class PowerPortBulkDeleteView(generic.BulkDeleteView): class PowerPortBulkDeleteView(generic.BulkDeleteView):
queryset = PowerPort.objects.all() queryset = PowerPort.objects.all()
filterset = filters.PowerPortFilterSet filterset = filtersets.PowerPortFilterSet
table = tables.PowerPortTable table = tables.PowerPortTable
@ -1797,7 +1799,7 @@ class PowerPortBulkDeleteView(generic.BulkDeleteView):
class PowerOutletListView(generic.ObjectListView): class PowerOutletListView(generic.ObjectListView):
queryset = PowerOutlet.objects.all() queryset = PowerOutlet.objects.all()
filterset = filters.PowerOutletFilterSet filterset = filtersets.PowerOutletFilterSet
filterset_form = forms.PowerOutletFilterForm filterset_form = forms.PowerOutletFilterForm
table = tables.PowerOutletTable table = tables.PowerOutletTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -1832,7 +1834,7 @@ class PowerOutletBulkImportView(generic.BulkImportView):
class PowerOutletBulkEditView(generic.BulkEditView): class PowerOutletBulkEditView(generic.BulkEditView):
queryset = PowerOutlet.objects.all() queryset = PowerOutlet.objects.all()
filterset = filters.PowerOutletFilterSet filterset = filtersets.PowerOutletFilterSet
table = tables.PowerOutletTable table = tables.PowerOutletTable
form = forms.PowerOutletBulkEditForm form = forms.PowerOutletBulkEditForm
@ -1847,7 +1849,7 @@ class PowerOutletBulkDisconnectView(BulkDisconnectView):
class PowerOutletBulkDeleteView(generic.BulkDeleteView): class PowerOutletBulkDeleteView(generic.BulkDeleteView):
queryset = PowerOutlet.objects.all() queryset = PowerOutlet.objects.all()
filterset = filters.PowerOutletFilterSet filterset = filtersets.PowerOutletFilterSet
table = tables.PowerOutletTable table = tables.PowerOutletTable
@ -1857,7 +1859,7 @@ class PowerOutletBulkDeleteView(generic.BulkDeleteView):
class InterfaceListView(generic.ObjectListView): class InterfaceListView(generic.ObjectListView):
queryset = Interface.objects.all() queryset = Interface.objects.all()
filterset = filters.InterfaceFilterSet filterset = filtersets.InterfaceFilterSet
filterset_form = forms.InterfaceFilterForm filterset_form = forms.InterfaceFilterForm
table = tables.InterfaceTable table = tables.InterfaceTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -1927,7 +1929,7 @@ class InterfaceBulkImportView(generic.BulkImportView):
class InterfaceBulkEditView(generic.BulkEditView): class InterfaceBulkEditView(generic.BulkEditView):
queryset = Interface.objects.all() queryset = Interface.objects.all()
filterset = filters.InterfaceFilterSet filterset = filtersets.InterfaceFilterSet
table = tables.InterfaceTable table = tables.InterfaceTable
form = forms.InterfaceBulkEditForm form = forms.InterfaceBulkEditForm
@ -1942,7 +1944,7 @@ class InterfaceBulkDisconnectView(BulkDisconnectView):
class InterfaceBulkDeleteView(generic.BulkDeleteView): class InterfaceBulkDeleteView(generic.BulkDeleteView):
queryset = Interface.objects.all() queryset = Interface.objects.all()
filterset = filters.InterfaceFilterSet filterset = filtersets.InterfaceFilterSet
table = tables.InterfaceTable table = tables.InterfaceTable
@ -1952,7 +1954,7 @@ class InterfaceBulkDeleteView(generic.BulkDeleteView):
class FrontPortListView(generic.ObjectListView): class FrontPortListView(generic.ObjectListView):
queryset = FrontPort.objects.all() queryset = FrontPort.objects.all()
filterset = filters.FrontPortFilterSet filterset = filtersets.FrontPortFilterSet
filterset_form = forms.FrontPortFilterForm filterset_form = forms.FrontPortFilterForm
table = tables.FrontPortTable table = tables.FrontPortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -1987,7 +1989,7 @@ class FrontPortBulkImportView(generic.BulkImportView):
class FrontPortBulkEditView(generic.BulkEditView): class FrontPortBulkEditView(generic.BulkEditView):
queryset = FrontPort.objects.all() queryset = FrontPort.objects.all()
filterset = filters.FrontPortFilterSet filterset = filtersets.FrontPortFilterSet
table = tables.FrontPortTable table = tables.FrontPortTable
form = forms.FrontPortBulkEditForm form = forms.FrontPortBulkEditForm
@ -2002,7 +2004,7 @@ class FrontPortBulkDisconnectView(BulkDisconnectView):
class FrontPortBulkDeleteView(generic.BulkDeleteView): class FrontPortBulkDeleteView(generic.BulkDeleteView):
queryset = FrontPort.objects.all() queryset = FrontPort.objects.all()
filterset = filters.FrontPortFilterSet filterset = filtersets.FrontPortFilterSet
table = tables.FrontPortTable table = tables.FrontPortTable
@ -2012,7 +2014,7 @@ class FrontPortBulkDeleteView(generic.BulkDeleteView):
class RearPortListView(generic.ObjectListView): class RearPortListView(generic.ObjectListView):
queryset = RearPort.objects.all() queryset = RearPort.objects.all()
filterset = filters.RearPortFilterSet filterset = filtersets.RearPortFilterSet
filterset_form = forms.RearPortFilterForm filterset_form = forms.RearPortFilterForm
table = tables.RearPortTable table = tables.RearPortTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -2047,7 +2049,7 @@ class RearPortBulkImportView(generic.BulkImportView):
class RearPortBulkEditView(generic.BulkEditView): class RearPortBulkEditView(generic.BulkEditView):
queryset = RearPort.objects.all() queryset = RearPort.objects.all()
filterset = filters.RearPortFilterSet filterset = filtersets.RearPortFilterSet
table = tables.RearPortTable table = tables.RearPortTable
form = forms.RearPortBulkEditForm form = forms.RearPortBulkEditForm
@ -2062,7 +2064,7 @@ class RearPortBulkDisconnectView(BulkDisconnectView):
class RearPortBulkDeleteView(generic.BulkDeleteView): class RearPortBulkDeleteView(generic.BulkDeleteView):
queryset = RearPort.objects.all() queryset = RearPort.objects.all()
filterset = filters.RearPortFilterSet filterset = filtersets.RearPortFilterSet
table = tables.RearPortTable table = tables.RearPortTable
@ -2072,7 +2074,7 @@ class RearPortBulkDeleteView(generic.BulkDeleteView):
class DeviceBayListView(generic.ObjectListView): class DeviceBayListView(generic.ObjectListView):
queryset = DeviceBay.objects.all() queryset = DeviceBay.objects.all()
filterset = filters.DeviceBayFilterSet filterset = filtersets.DeviceBayFilterSet
filterset_form = forms.DeviceBayFilterForm filterset_form = forms.DeviceBayFilterForm
table = tables.DeviceBayTable table = tables.DeviceBayTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -2172,7 +2174,7 @@ class DeviceBayBulkImportView(generic.BulkImportView):
class DeviceBayBulkEditView(generic.BulkEditView): class DeviceBayBulkEditView(generic.BulkEditView):
queryset = DeviceBay.objects.all() queryset = DeviceBay.objects.all()
filterset = filters.DeviceBayFilterSet filterset = filtersets.DeviceBayFilterSet
table = tables.DeviceBayTable table = tables.DeviceBayTable
form = forms.DeviceBayBulkEditForm form = forms.DeviceBayBulkEditForm
@ -2183,7 +2185,7 @@ class DeviceBayBulkRenameView(generic.BulkRenameView):
class DeviceBayBulkDeleteView(generic.BulkDeleteView): class DeviceBayBulkDeleteView(generic.BulkDeleteView):
queryset = DeviceBay.objects.all() queryset = DeviceBay.objects.all()
filterset = filters.DeviceBayFilterSet filterset = filtersets.DeviceBayFilterSet
table = tables.DeviceBayTable table = tables.DeviceBayTable
@ -2193,7 +2195,7 @@ class DeviceBayBulkDeleteView(generic.BulkDeleteView):
class InventoryItemListView(generic.ObjectListView): class InventoryItemListView(generic.ObjectListView):
queryset = InventoryItem.objects.all() queryset = InventoryItem.objects.all()
filterset = filters.InventoryItemFilterSet filterset = filtersets.InventoryItemFilterSet
filterset_form = forms.InventoryItemFilterForm filterset_form = forms.InventoryItemFilterForm
table = tables.InventoryItemTable table = tables.InventoryItemTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -2227,7 +2229,7 @@ class InventoryItemBulkImportView(generic.BulkImportView):
class InventoryItemBulkEditView(generic.BulkEditView): class InventoryItemBulkEditView(generic.BulkEditView):
queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer') queryset = InventoryItem.objects.prefetch_related('device', 'manufacturer')
filterset = filters.InventoryItemFilterSet filterset = filtersets.InventoryItemFilterSet
table = tables.InventoryItemTable table = tables.InventoryItemTable
form = forms.InventoryItemBulkEditForm form = forms.InventoryItemBulkEditForm
@ -2252,7 +2254,7 @@ class DeviceBulkAddConsolePortView(generic.BulkComponentCreateView):
form = forms.ConsolePortBulkCreateForm form = forms.ConsolePortBulkCreateForm
queryset = ConsolePort.objects.all() queryset = ConsolePort.objects.all()
model_form = forms.ConsolePortForm model_form = forms.ConsolePortForm
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
@ -2263,7 +2265,7 @@ class DeviceBulkAddConsoleServerPortView(generic.BulkComponentCreateView):
form = forms.ConsoleServerPortBulkCreateForm form = forms.ConsoleServerPortBulkCreateForm
queryset = ConsoleServerPort.objects.all() queryset = ConsoleServerPort.objects.all()
model_form = forms.ConsoleServerPortForm model_form = forms.ConsoleServerPortForm
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
@ -2274,7 +2276,7 @@ class DeviceBulkAddPowerPortView(generic.BulkComponentCreateView):
form = forms.PowerPortBulkCreateForm form = forms.PowerPortBulkCreateForm
queryset = PowerPort.objects.all() queryset = PowerPort.objects.all()
model_form = forms.PowerPortForm model_form = forms.PowerPortForm
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
@ -2285,7 +2287,7 @@ class DeviceBulkAddPowerOutletView(generic.BulkComponentCreateView):
form = forms.PowerOutletBulkCreateForm form = forms.PowerOutletBulkCreateForm
queryset = PowerOutlet.objects.all() queryset = PowerOutlet.objects.all()
model_form = forms.PowerOutletForm model_form = forms.PowerOutletForm
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
@ -2296,7 +2298,7 @@ class DeviceBulkAddInterfaceView(generic.BulkComponentCreateView):
form = forms.InterfaceBulkCreateForm form = forms.InterfaceBulkCreateForm
queryset = Interface.objects.all() queryset = Interface.objects.all()
model_form = forms.InterfaceForm model_form = forms.InterfaceForm
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
@ -2307,7 +2309,7 @@ class DeviceBulkAddInterfaceView(generic.BulkComponentCreateView):
# form = forms.FrontPortBulkCreateForm # form = forms.FrontPortBulkCreateForm
# queryset = FrontPort.objects.all() # queryset = FrontPort.objects.all()
# model_form = forms.FrontPortForm # model_form = forms.FrontPortForm
# filterset = filters.DeviceFilterSet # filterset = filtersets.DeviceFilterSet
# table = tables.DeviceTable # table = tables.DeviceTable
# default_return_url = 'dcim:device_list' # default_return_url = 'dcim:device_list'
@ -2318,7 +2320,7 @@ class DeviceBulkAddRearPortView(generic.BulkComponentCreateView):
form = forms.RearPortBulkCreateForm form = forms.RearPortBulkCreateForm
queryset = RearPort.objects.all() queryset = RearPort.objects.all()
model_form = forms.RearPortForm model_form = forms.RearPortForm
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
@ -2329,7 +2331,7 @@ class DeviceBulkAddDeviceBayView(generic.BulkComponentCreateView):
form = forms.DeviceBayBulkCreateForm form = forms.DeviceBayBulkCreateForm
queryset = DeviceBay.objects.all() queryset = DeviceBay.objects.all()
model_form = forms.DeviceBayForm model_form = forms.DeviceBayForm
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
@ -2340,7 +2342,7 @@ class DeviceBulkAddInventoryItemView(generic.BulkComponentCreateView):
form = forms.InventoryItemBulkCreateForm form = forms.InventoryItemBulkCreateForm
queryset = InventoryItem.objects.all() queryset = InventoryItem.objects.all()
model_form = forms.InventoryItemForm model_form = forms.InventoryItemForm
filterset = filters.DeviceFilterSet filterset = filtersets.DeviceFilterSet
table = tables.DeviceTable table = tables.DeviceTable
default_return_url = 'dcim:device_list' default_return_url = 'dcim:device_list'
@ -2351,7 +2353,7 @@ class DeviceBulkAddInventoryItemView(generic.BulkComponentCreateView):
class CableListView(generic.ObjectListView): class CableListView(generic.ObjectListView):
queryset = Cable.objects.all() queryset = Cable.objects.all()
filterset = filters.CableFilterSet filterset = filtersets.CableFilterSet
filterset_form = forms.CableFilterForm filterset_form = forms.CableFilterForm
table = tables.CableTable table = tables.CableTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -2484,14 +2486,14 @@ class CableBulkImportView(generic.BulkImportView):
class CableBulkEditView(generic.BulkEditView): class CableBulkEditView(generic.BulkEditView):
queryset = Cable.objects.prefetch_related('termination_a', 'termination_b') queryset = Cable.objects.prefetch_related('termination_a', 'termination_b')
filterset = filters.CableFilterSet filterset = filtersets.CableFilterSet
table = tables.CableTable table = tables.CableTable
form = forms.CableBulkEditForm form = forms.CableBulkEditForm
class CableBulkDeleteView(generic.BulkDeleteView): class CableBulkDeleteView(generic.BulkDeleteView):
queryset = Cable.objects.prefetch_related('termination_a', 'termination_b') queryset = Cable.objects.prefetch_related('termination_a', 'termination_b')
filterset = filters.CableFilterSet filterset = filtersets.CableFilterSet
table = tables.CableTable table = tables.CableTable
@ -2501,7 +2503,7 @@ class CableBulkDeleteView(generic.BulkDeleteView):
class ConsoleConnectionsListView(generic.ObjectListView): class ConsoleConnectionsListView(generic.ObjectListView):
queryset = ConsolePort.objects.filter(_path__isnull=False).order_by('device') queryset = ConsolePort.objects.filter(_path__isnull=False).order_by('device')
filterset = filters.ConsoleConnectionFilterSet filterset = filtersets.ConsoleConnectionFilterSet
filterset_form = forms.ConsoleConnectionFilterForm filterset_form = forms.ConsoleConnectionFilterForm
table = tables.ConsoleConnectionTable table = tables.ConsoleConnectionTable
template_name = 'dcim/connections_list.html' template_name = 'dcim/connections_list.html'
@ -2531,7 +2533,7 @@ class ConsoleConnectionsListView(generic.ObjectListView):
class PowerConnectionsListView(generic.ObjectListView): class PowerConnectionsListView(generic.ObjectListView):
queryset = PowerPort.objects.filter(_path__isnull=False).order_by('device') queryset = PowerPort.objects.filter(_path__isnull=False).order_by('device')
filterset = filters.PowerConnectionFilterSet filterset = filtersets.PowerConnectionFilterSet
filterset_form = forms.PowerConnectionFilterForm filterset_form = forms.PowerConnectionFilterForm
table = tables.PowerConnectionTable table = tables.PowerConnectionTable
template_name = 'dcim/connections_list.html' template_name = 'dcim/connections_list.html'
@ -2565,7 +2567,7 @@ class InterfaceConnectionsListView(generic.ObjectListView):
_path__isnull=False, _path__isnull=False,
pk__lt=F('_path__destination_id') pk__lt=F('_path__destination_id')
).order_by('device') ).order_by('device')
filterset = filters.InterfaceConnectionFilterSet filterset = filtersets.InterfaceConnectionFilterSet
filterset_form = forms.InterfaceConnectionFilterForm filterset_form = forms.InterfaceConnectionFilterForm
table = tables.InterfaceConnectionTable table = tables.InterfaceConnectionTable
template_name = 'dcim/connections_list.html' template_name = 'dcim/connections_list.html'
@ -2604,7 +2606,7 @@ class VirtualChassisListView(generic.ObjectListView):
member_count=count_related(Device, 'virtual_chassis') member_count=count_related(Device, 'virtual_chassis')
) )
table = tables.VirtualChassisTable table = tables.VirtualChassisTable
filterset = filters.VirtualChassisFilterSet filterset = filtersets.VirtualChassisFilterSet
filterset_form = forms.VirtualChassisFilterForm filterset_form = forms.VirtualChassisFilterForm
@ -2812,14 +2814,14 @@ class VirtualChassisBulkImportView(generic.BulkImportView):
class VirtualChassisBulkEditView(generic.BulkEditView): class VirtualChassisBulkEditView(generic.BulkEditView):
queryset = VirtualChassis.objects.all() queryset = VirtualChassis.objects.all()
filterset = filters.VirtualChassisFilterSet filterset = filtersets.VirtualChassisFilterSet
table = tables.VirtualChassisTable table = tables.VirtualChassisTable
form = forms.VirtualChassisBulkEditForm form = forms.VirtualChassisBulkEditForm
class VirtualChassisBulkDeleteView(generic.BulkDeleteView): class VirtualChassisBulkDeleteView(generic.BulkDeleteView):
queryset = VirtualChassis.objects.all() queryset = VirtualChassis.objects.all()
filterset = filters.VirtualChassisFilterSet filterset = filtersets.VirtualChassisFilterSet
table = tables.VirtualChassisTable table = tables.VirtualChassisTable
@ -2833,7 +2835,7 @@ class PowerPanelListView(generic.ObjectListView):
).annotate( ).annotate(
powerfeed_count=count_related(PowerFeed, 'power_panel') powerfeed_count=count_related(PowerFeed, 'power_panel')
) )
filterset = filters.PowerPanelFilterSet filterset = filtersets.PowerPanelFilterSet
filterset_form = forms.PowerPanelFilterForm filterset_form = forms.PowerPanelFilterForm
table = tables.PowerPanelTable table = tables.PowerPanelTable
@ -2873,7 +2875,7 @@ class PowerPanelBulkImportView(generic.BulkImportView):
class PowerPanelBulkEditView(generic.BulkEditView): class PowerPanelBulkEditView(generic.BulkEditView):
queryset = PowerPanel.objects.prefetch_related('site', 'location') queryset = PowerPanel.objects.prefetch_related('site', 'location')
filterset = filters.PowerPanelFilterSet filterset = filtersets.PowerPanelFilterSet
table = tables.PowerPanelTable table = tables.PowerPanelTable
form = forms.PowerPanelBulkEditForm form = forms.PowerPanelBulkEditForm
@ -2884,7 +2886,7 @@ class PowerPanelBulkDeleteView(generic.BulkDeleteView):
).annotate( ).annotate(
powerfeed_count=count_related(PowerFeed, 'power_panel') powerfeed_count=count_related(PowerFeed, 'power_panel')
) )
filterset = filters.PowerPanelFilterSet filterset = filtersets.PowerPanelFilterSet
table = tables.PowerPanelTable table = tables.PowerPanelTable
@ -2894,7 +2896,7 @@ class PowerPanelBulkDeleteView(generic.BulkDeleteView):
class PowerFeedListView(generic.ObjectListView): class PowerFeedListView(generic.ObjectListView):
queryset = PowerFeed.objects.all() queryset = PowerFeed.objects.all()
filterset = filters.PowerFeedFilterSet filterset = filtersets.PowerFeedFilterSet
filterset_form = forms.PowerFeedFilterForm filterset_form = forms.PowerFeedFilterForm
table = tables.PowerFeedTable table = tables.PowerFeedTable
@ -2920,7 +2922,7 @@ class PowerFeedBulkImportView(generic.BulkImportView):
class PowerFeedBulkEditView(generic.BulkEditView): class PowerFeedBulkEditView(generic.BulkEditView):
queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack') queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack')
filterset = filters.PowerFeedFilterSet filterset = filtersets.PowerFeedFilterSet
table = tables.PowerFeedTable table = tables.PowerFeedTable
form = forms.PowerFeedBulkEditForm form = forms.PowerFeedBulkEditForm
@ -2931,5 +2933,5 @@ class PowerFeedBulkDisconnectView(BulkDisconnectView):
class PowerFeedBulkDeleteView(generic.BulkDeleteView): class PowerFeedBulkDeleteView(generic.BulkDeleteView):
queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack') queryset = PowerFeed.objects.prefetch_related('power_panel', 'rack')
filterset = filters.PowerFeedFilterSet filterset = filtersets.PowerFeedFilterSet
table = tables.PowerFeedTable table = tables.PowerFeedTable

View File

@ -9,7 +9,7 @@ from rest_framework.routers import APIRootView
from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet from rest_framework.viewsets import ReadOnlyModelViewSet, ViewSet
from rq import Worker from rq import Worker
from extras import filters from extras import filtersets
from extras.choices import JobResultStatusChoices from extras.choices import JobResultStatusChoices
from extras.models import * from extras.models import *
from extras.models import CustomField from extras.models import CustomField
@ -61,7 +61,7 @@ class WebhookViewSet(ModelViewSet):
metadata_class = ContentTypeMetadata metadata_class = ContentTypeMetadata
queryset = Webhook.objects.all() queryset = Webhook.objects.all()
serializer_class = serializers.WebhookSerializer serializer_class = serializers.WebhookSerializer
filterset_class = filters.WebhookFilterSet filterset_class = filtersets.WebhookFilterSet
# #
@ -72,7 +72,7 @@ class CustomFieldViewSet(ModelViewSet):
metadata_class = ContentTypeMetadata metadata_class = ContentTypeMetadata
queryset = CustomField.objects.all() queryset = CustomField.objects.all()
serializer_class = serializers.CustomFieldSerializer serializer_class = serializers.CustomFieldSerializer
filterset_class = filters.CustomFieldFilterSet filterset_class = filtersets.CustomFieldFilterSet
class CustomFieldModelViewSet(ModelViewSet): class CustomFieldModelViewSet(ModelViewSet):
@ -101,7 +101,7 @@ class CustomLinkViewSet(ModelViewSet):
metadata_class = ContentTypeMetadata metadata_class = ContentTypeMetadata
queryset = CustomLink.objects.all() queryset = CustomLink.objects.all()
serializer_class = serializers.CustomLinkSerializer serializer_class = serializers.CustomLinkSerializer
filterset_class = filters.CustomLinkFilterSet filterset_class = filtersets.CustomLinkFilterSet
# #
@ -112,7 +112,7 @@ class ExportTemplateViewSet(ModelViewSet):
metadata_class = ContentTypeMetadata metadata_class = ContentTypeMetadata
queryset = ExportTemplate.objects.all() queryset = ExportTemplate.objects.all()
serializer_class = serializers.ExportTemplateSerializer serializer_class = serializers.ExportTemplateSerializer
filterset_class = filters.ExportTemplateFilterSet filterset_class = filtersets.ExportTemplateFilterSet
# #
@ -124,7 +124,7 @@ class TagViewSet(ModelViewSet):
tagged_items=count_related(TaggedItem, 'tag') tagged_items=count_related(TaggedItem, 'tag')
) )
serializer_class = serializers.TagSerializer serializer_class = serializers.TagSerializer
filterset_class = filters.TagFilterSet filterset_class = filtersets.TagFilterSet
# #
@ -135,7 +135,7 @@ class ImageAttachmentViewSet(ModelViewSet):
metadata_class = ContentTypeMetadata metadata_class = ContentTypeMetadata
queryset = ImageAttachment.objects.all() queryset = ImageAttachment.objects.all()
serializer_class = serializers.ImageAttachmentSerializer serializer_class = serializers.ImageAttachmentSerializer
filterset_class = filters.ImageAttachmentFilterSet filterset_class = filtersets.ImageAttachmentFilterSet
# #
@ -146,7 +146,7 @@ class JournalEntryViewSet(ModelViewSet):
metadata_class = ContentTypeMetadata metadata_class = ContentTypeMetadata
queryset = JournalEntry.objects.all() queryset = JournalEntry.objects.all()
serializer_class = serializers.JournalEntrySerializer serializer_class = serializers.JournalEntrySerializer
filterset_class = filters.JournalEntryFilterSet filterset_class = filtersets.JournalEntryFilterSet
# #
@ -158,7 +158,7 @@ class ConfigContextViewSet(ModelViewSet):
'regions', 'site_groups', 'sites', 'roles', 'platforms', 'tenant_groups', 'tenants', 'regions', 'site_groups', 'sites', 'roles', 'platforms', 'tenant_groups', 'tenants',
) )
serializer_class = serializers.ConfigContextSerializer serializer_class = serializers.ConfigContextSerializer
filterset_class = filters.ConfigContextFilterSet filterset_class = filtersets.ConfigContextFilterSet
# #
@ -358,7 +358,7 @@ class ObjectChangeViewSet(ReadOnlyModelViewSet):
metadata_class = ContentTypeMetadata metadata_class = ContentTypeMetadata
queryset = ObjectChange.objects.prefetch_related('user') queryset = ObjectChange.objects.prefetch_related('user')
serializer_class = serializers.ObjectChangeSerializer serializer_class = serializers.ObjectChangeSerializer
filterset_class = filters.ObjectChangeFilterSet filterset_class = filtersets.ObjectChangeFilterSet
# #
@ -371,7 +371,7 @@ class JobResultViewSet(ReadOnlyModelViewSet):
""" """
queryset = JobResult.objects.prefetch_related('user') queryset = JobResult.objects.prefetch_related('user')
serializer_class = serializers.JobResultSerializer serializer_class = serializers.JobResultSerializer
filterset_class = filters.JobResultFilterSet filterset_class = filtersets.JobResultFilterSet
# #
@ -384,4 +384,4 @@ class ContentTypeViewSet(ReadOnlyModelViewSet):
""" """
queryset = ContentType.objects.order_by('app_label', 'model') queryset = ContentType.objects.order_by('app_label', 'model')
serializer_class = serializers.ContentTypeSerializer serializer_class = serializers.ContentTypeSerializer
filterset_class = filters.ContentTypeFilterSet filterset_class = filtersets.ContentTypeFilterSet

View File

@ -1,31 +1,12 @@
import django_filters import django_filters
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.forms import DateField, IntegerField, NullBooleanField from django.forms import DateField, IntegerField, NullBooleanField
from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup from .models import Tag
from tenancy.models import Tenant, TenantGroup
from utilities.filters import BaseFilterSet, ContentTypeFilter
from virtualization.models import Cluster, ClusterGroup
from .choices import * from .choices import *
from .models import *
__all__ = ( __all__ = (
'ConfigContextFilterSet',
'ContentTypeFilterSet',
'CreatedUpdatedFilterSet',
'CustomFieldFilter', 'CustomFieldFilter',
'CustomLinkFilterSet', 'TagFilter',
'CustomFieldModelFilterSet',
'ExportTemplateFilterSet',
'ImageAttachmentFilterSet',
'JournalEntryFilterSet',
'LocalConfigContextFilterSet',
'ObjectChangeFilterSet',
'TagFilterSet',
'WebhookFilterSet',
) )
EXACT_FILTER_TYPES = ( EXACT_FILTER_TYPES = (
@ -36,41 +17,6 @@ EXACT_FILTER_TYPES = (
) )
class CreatedUpdatedFilterSet(django_filters.FilterSet):
created = django_filters.DateFilter()
created__gte = django_filters.DateFilter(
field_name='created',
lookup_expr='gte'
)
created__lte = django_filters.DateFilter(
field_name='created',
lookup_expr='lte'
)
last_updated = django_filters.DateTimeFilter()
last_updated__gte = django_filters.DateTimeFilter(
field_name='last_updated',
lookup_expr='gte'
)
last_updated__lte = django_filters.DateTimeFilter(
field_name='last_updated',
lookup_expr='lte'
)
class WebhookFilterSet(BaseFilterSet):
content_types = ContentTypeFilter()
http_method = django_filters.MultipleChoiceFilter(
choices=WebhookHttpMethodChoices
)
class Meta:
model = Webhook
fields = [
'id', 'content_types', 'name', 'type_create', 'type_update', 'type_delete', 'payload_url', 'enabled',
'http_method', 'http_content_type', 'secret', 'ssl_verification', 'ca_file_path',
]
class CustomFieldFilter(django_filters.Filter): class CustomFieldFilter(django_filters.Filter):
""" """
Filter objects by the presence of a CustomFieldValue. The filter's name is used as the CustomField name. Filter objects by the presence of a CustomFieldValue. The filter's name is used as the CustomField name.
@ -94,310 +40,16 @@ class CustomFieldFilter(django_filters.Filter):
self.lookup_expr = 'icontains' self.lookup_expr = 'icontains'
class CustomFieldModelFilterSet(django_filters.FilterSet): class TagFilter(django_filters.ModelMultipleChoiceFilter):
""" """
Dynamically add a Filter for each CustomField applicable to the parent model. Match on one or more assigned tags. If multiple tags are specified (e.g. ?tag=foo&tag=bar), the queryset is filtered
to objects matching all tags.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs.setdefault('field_name', 'tags__slug')
kwargs.setdefault('to_field_name', 'slug')
kwargs.setdefault('conjoined', True)
kwargs.setdefault('queryset', Tag.objects.all())
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
custom_fields = CustomField.objects.filter(
content_types=ContentType.objects.get_for_model(self._meta.model)
).exclude(
filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED
)
for cf in custom_fields:
self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(field_name=cf.name, custom_field=cf)
class CustomFieldFilterSet(django_filters.FilterSet):
content_types = ContentTypeFilter()
class Meta:
model = CustomField
fields = ['id', 'content_types', 'name', 'required', 'filter_logic', 'weight']
class CustomLinkFilterSet(BaseFilterSet):
class Meta:
model = CustomLink
fields = ['id', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name', 'new_window']
class ExportTemplateFilterSet(BaseFilterSet):
class Meta:
model = ExportTemplate
fields = ['id', 'content_type', 'name']
class ImageAttachmentFilterSet(BaseFilterSet):
content_type = ContentTypeFilter()
class Meta:
model = ImageAttachment
fields = ['id', 'content_type_id', 'object_id', 'name']
class JournalEntryFilterSet(BaseFilterSet, CreatedUpdatedFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
created = django_filters.DateTimeFromToRangeFilter()
assigned_object_type = ContentTypeFilter()
created_by_id = django_filters.ModelMultipleChoiceFilter(
queryset=User.objects.all(),
label='User (ID)',
)
created_by = django_filters.ModelMultipleChoiceFilter(
field_name='created_by__username',
queryset=User.objects.all(),
to_field_name='username',
label='User (name)',
)
kind = django_filters.MultipleChoiceFilter(
choices=JournalEntryKindChoices
)
class Meta:
model = JournalEntry
fields = ['id', 'assigned_object_type_id', 'assigned_object_id', 'created', 'kind']
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(comments__icontains=value)
class TagFilterSet(BaseFilterSet, CreatedUpdatedFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
class Meta:
model = Tag
fields = ['id', 'name', 'slug', 'color']
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(name__icontains=value) |
Q(slug__icontains=value)
)
class ConfigContextFilterSet(BaseFilterSet, CreatedUpdatedFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
region_id = django_filters.ModelMultipleChoiceFilter(
field_name='regions',
queryset=Region.objects.all(),
label='Region',
)
region = django_filters.ModelMultipleChoiceFilter(
field_name='regions__slug',
queryset=Region.objects.all(),
to_field_name='slug',
label='Region (slug)',
)
site_group = django_filters.ModelMultipleChoiceFilter(
field_name='site_groups__slug',
queryset=SiteGroup.objects.all(),
to_field_name='slug',
label='Site group (slug)',
)
site_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='site_groups',
queryset=SiteGroup.objects.all(),
label='Site group',
)
site_id = django_filters.ModelMultipleChoiceFilter(
field_name='sites',
queryset=Site.objects.all(),
label='Site',
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='sites__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label='Site (slug)',
)
device_type_id = django_filters.ModelMultipleChoiceFilter(
field_name='device_types',
queryset=DeviceType.objects.all(),
label='Device type',
)
role_id = django_filters.ModelMultipleChoiceFilter(
field_name='roles',
queryset=DeviceRole.objects.all(),
label='Role',
)
role = django_filters.ModelMultipleChoiceFilter(
field_name='roles__slug',
queryset=DeviceRole.objects.all(),
to_field_name='slug',
label='Role (slug)',
)
platform_id = django_filters.ModelMultipleChoiceFilter(
field_name='platforms',
queryset=Platform.objects.all(),
label='Platform',
)
platform = django_filters.ModelMultipleChoiceFilter(
field_name='platforms__slug',
queryset=Platform.objects.all(),
to_field_name='slug',
label='Platform (slug)',
)
cluster_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='cluster_groups',
queryset=ClusterGroup.objects.all(),
label='Cluster group',
)
cluster_group = django_filters.ModelMultipleChoiceFilter(
field_name='cluster_groups__slug',
queryset=ClusterGroup.objects.all(),
to_field_name='slug',
label='Cluster group (slug)',
)
cluster_id = django_filters.ModelMultipleChoiceFilter(
field_name='clusters',
queryset=Cluster.objects.all(),
label='Cluster',
)
tenant_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='tenant_groups',
queryset=TenantGroup.objects.all(),
label='Tenant group',
)
tenant_group = django_filters.ModelMultipleChoiceFilter(
field_name='tenant_groups__slug',
queryset=TenantGroup.objects.all(),
to_field_name='slug',
label='Tenant group (slug)',
)
tenant_id = django_filters.ModelMultipleChoiceFilter(
field_name='tenants',
queryset=Tenant.objects.all(),
label='Tenant',
)
tenant = django_filters.ModelMultipleChoiceFilter(
field_name='tenants__slug',
queryset=Tenant.objects.all(),
to_field_name='slug',
label='Tenant (slug)',
)
tag = django_filters.ModelMultipleChoiceFilter(
field_name='tags__slug',
queryset=Tag.objects.all(),
to_field_name='slug',
label='Tag (slug)',
)
class Meta:
model = ConfigContext
fields = ['id', 'name', 'is_active']
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(name__icontains=value) |
Q(description__icontains=value) |
Q(data__icontains=value)
)
#
# Filter for Local Config Context Data
#
class LocalConfigContextFilterSet(django_filters.FilterSet):
local_context_data = django_filters.BooleanFilter(
method='_local_context_data',
label='Has local config context data',
)
def _local_context_data(self, queryset, name, value):
return queryset.exclude(local_context_data__isnull=value)
class ObjectChangeFilterSet(BaseFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
time = django_filters.DateTimeFromToRangeFilter()
changed_object_type = ContentTypeFilter()
user_id = django_filters.ModelMultipleChoiceFilter(
queryset=User.objects.all(),
label='User (ID)',
)
user = django_filters.ModelMultipleChoiceFilter(
field_name='user__username',
queryset=User.objects.all(),
to_field_name='username',
label='User name',
)
class Meta:
model = ObjectChange
fields = [
'id', 'user', 'user_name', 'request_id', 'action', 'changed_object_type_id', 'changed_object_id',
'object_repr',
]
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(user_name__icontains=value) |
Q(object_repr__icontains=value)
)
#
# Job Results
#
class JobResultFilterSet(BaseFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
created = django_filters.DateTimeFilter()
completed = django_filters.DateTimeFilter()
status = django_filters.MultipleChoiceFilter(
choices=JobResultStatusChoices,
null_value=None
)
class Meta:
model = JobResult
fields = [
'id', 'created', 'completed', 'status', 'user', 'obj_type', 'name'
]
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(user__username__icontains=value)
)
#
# ContentTypes
#
class ContentTypeFilterSet(django_filters.FilterSet):
class Meta:
model = ContentType
fields = ['id', 'app_label', 'model']

341
netbox/extras/filtersets.py Normal file
View File

@ -0,0 +1,341 @@
import django_filters
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from dcim.models import DeviceRole, DeviceType, Platform, Region, Site, SiteGroup
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet
from tenancy.models import Tenant, TenantGroup
from utilities.filters import ContentTypeFilter
from virtualization.models import Cluster, ClusterGroup
from .choices import *
from .models import *
__all__ = (
'ConfigContextFilterSet',
'ContentTypeFilterSet',
'CustomLinkFilterSet',
'ExportTemplateFilterSet',
'ImageAttachmentFilterSet',
'JournalEntryFilterSet',
'LocalConfigContextFilterSet',
'ObjectChangeFilterSet',
'TagFilterSet',
'WebhookFilterSet',
)
EXACT_FILTER_TYPES = (
CustomFieldTypeChoices.TYPE_BOOLEAN,
CustomFieldTypeChoices.TYPE_DATE,
CustomFieldTypeChoices.TYPE_INTEGER,
CustomFieldTypeChoices.TYPE_SELECT,
)
class WebhookFilterSet(BaseFilterSet):
content_types = ContentTypeFilter()
http_method = django_filters.MultipleChoiceFilter(
choices=WebhookHttpMethodChoices
)
class Meta:
model = Webhook
fields = [
'id', 'content_types', 'name', 'type_create', 'type_update', 'type_delete', 'payload_url', 'enabled',
'http_method', 'http_content_type', 'secret', 'ssl_verification', 'ca_file_path',
]
class CustomFieldFilterSet(django_filters.FilterSet):
content_types = ContentTypeFilter()
class Meta:
model = CustomField
fields = ['id', 'content_types', 'name', 'required', 'filter_logic', 'weight']
class CustomLinkFilterSet(BaseFilterSet):
class Meta:
model = CustomLink
fields = ['id', 'content_type', 'name', 'link_text', 'link_url', 'weight', 'group_name', 'new_window']
class ExportTemplateFilterSet(BaseFilterSet):
class Meta:
model = ExportTemplate
fields = ['id', 'content_type', 'name']
class ImageAttachmentFilterSet(BaseFilterSet):
created = django_filters.DateTimeFilter()
content_type = ContentTypeFilter()
class Meta:
model = ImageAttachment
fields = ['id', 'content_type_id', 'object_id', 'name']
class JournalEntryFilterSet(ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
created = django_filters.DateTimeFromToRangeFilter()
assigned_object_type = ContentTypeFilter()
created_by_id = django_filters.ModelMultipleChoiceFilter(
queryset=User.objects.all(),
label='User (ID)',
)
created_by = django_filters.ModelMultipleChoiceFilter(
field_name='created_by__username',
queryset=User.objects.all(),
to_field_name='username',
label='User (name)',
)
kind = django_filters.MultipleChoiceFilter(
choices=JournalEntryKindChoices
)
class Meta:
model = JournalEntry
fields = ['id', 'assigned_object_type_id', 'assigned_object_id', 'created', 'kind']
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(comments__icontains=value)
class TagFilterSet(ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
class Meta:
model = Tag
fields = ['id', 'name', 'slug', 'color']
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(name__icontains=value) |
Q(slug__icontains=value)
)
class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
region_id = django_filters.ModelMultipleChoiceFilter(
field_name='regions',
queryset=Region.objects.all(),
label='Region',
)
region = django_filters.ModelMultipleChoiceFilter(
field_name='regions__slug',
queryset=Region.objects.all(),
to_field_name='slug',
label='Region (slug)',
)
site_group = django_filters.ModelMultipleChoiceFilter(
field_name='site_groups__slug',
queryset=SiteGroup.objects.all(),
to_field_name='slug',
label='Site group (slug)',
)
site_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='site_groups',
queryset=SiteGroup.objects.all(),
label='Site group',
)
site_id = django_filters.ModelMultipleChoiceFilter(
field_name='sites',
queryset=Site.objects.all(),
label='Site',
)
site = django_filters.ModelMultipleChoiceFilter(
field_name='sites__slug',
queryset=Site.objects.all(),
to_field_name='slug',
label='Site (slug)',
)
device_type_id = django_filters.ModelMultipleChoiceFilter(
field_name='device_types',
queryset=DeviceType.objects.all(),
label='Device type',
)
role_id = django_filters.ModelMultipleChoiceFilter(
field_name='roles',
queryset=DeviceRole.objects.all(),
label='Role',
)
role = django_filters.ModelMultipleChoiceFilter(
field_name='roles__slug',
queryset=DeviceRole.objects.all(),
to_field_name='slug',
label='Role (slug)',
)
platform_id = django_filters.ModelMultipleChoiceFilter(
field_name='platforms',
queryset=Platform.objects.all(),
label='Platform',
)
platform = django_filters.ModelMultipleChoiceFilter(
field_name='platforms__slug',
queryset=Platform.objects.all(),
to_field_name='slug',
label='Platform (slug)',
)
cluster_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='cluster_groups',
queryset=ClusterGroup.objects.all(),
label='Cluster group',
)
cluster_group = django_filters.ModelMultipleChoiceFilter(
field_name='cluster_groups__slug',
queryset=ClusterGroup.objects.all(),
to_field_name='slug',
label='Cluster group (slug)',
)
cluster_id = django_filters.ModelMultipleChoiceFilter(
field_name='clusters',
queryset=Cluster.objects.all(),
label='Cluster',
)
tenant_group_id = django_filters.ModelMultipleChoiceFilter(
field_name='tenant_groups',
queryset=TenantGroup.objects.all(),
label='Tenant group',
)
tenant_group = django_filters.ModelMultipleChoiceFilter(
field_name='tenant_groups__slug',
queryset=TenantGroup.objects.all(),
to_field_name='slug',
label='Tenant group (slug)',
)
tenant_id = django_filters.ModelMultipleChoiceFilter(
field_name='tenants',
queryset=Tenant.objects.all(),
label='Tenant',
)
tenant = django_filters.ModelMultipleChoiceFilter(
field_name='tenants__slug',
queryset=Tenant.objects.all(),
to_field_name='slug',
label='Tenant (slug)',
)
tag = django_filters.ModelMultipleChoiceFilter(
field_name='tags__slug',
queryset=Tag.objects.all(),
to_field_name='slug',
label='Tag (slug)',
)
class Meta:
model = ConfigContext
fields = ['id', 'name', 'is_active']
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(name__icontains=value) |
Q(description__icontains=value) |
Q(data__icontains=value)
)
#
# Filter for Local Config Context Data
#
class LocalConfigContextFilterSet(django_filters.FilterSet):
local_context_data = django_filters.BooleanFilter(
method='_local_context_data',
label='Has local config context data',
)
def _local_context_data(self, queryset, name, value):
return queryset.exclude(local_context_data__isnull=value)
class ObjectChangeFilterSet(BaseFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
time = django_filters.DateTimeFromToRangeFilter()
changed_object_type = ContentTypeFilter()
user_id = django_filters.ModelMultipleChoiceFilter(
queryset=User.objects.all(),
label='User (ID)',
)
user = django_filters.ModelMultipleChoiceFilter(
field_name='user__username',
queryset=User.objects.all(),
to_field_name='username',
label='User name',
)
class Meta:
model = ObjectChange
fields = [
'id', 'user', 'user_name', 'request_id', 'action', 'changed_object_type_id', 'changed_object_id',
'object_repr',
]
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(user_name__icontains=value) |
Q(object_repr__icontains=value)
)
#
# Job Results
#
class JobResultFilterSet(BaseFilterSet):
q = django_filters.CharFilter(
method='search',
label='Search',
)
created = django_filters.DateTimeFilter()
completed = django_filters.DateTimeFilter()
status = django_filters.MultipleChoiceFilter(
choices=JobResultStatusChoices,
null_value=None
)
class Meta:
model = JobResult
fields = [
'id', 'created', 'completed', 'status', 'user', 'obj_type', 'name'
]
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
Q(user__username__icontains=value)
)
#
# ContentTypes
#
class ContentTypeFilterSet(django_filters.FilterSet):
class Meta:
model = ContentType
fields = ['id', 'app_label', 'model']

View File

@ -3,7 +3,7 @@ from django.core.exceptions import ValidationError
from django.urls import reverse from django.urls import reverse
from rest_framework import status from rest_framework import status
from dcim.filters import SiteFilterSet from dcim.filtersets import SiteFilterSet
from dcim.forms import SiteCSVForm from dcim.forms import SiteCSVForm
from dcim.models import Site, Rack from dcim.models import Site, Rack
from extras.choices import * from extras.choices import *

View File

@ -1,4 +1,5 @@
import uuid import uuid
from datetime import datetime, timezone
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
@ -6,14 +7,15 @@ from django.test import TestCase
from dcim.models import DeviceRole, DeviceType, Manufacturer, Platform, Rack, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Manufacturer, Platform, Rack, Region, Site, SiteGroup
from extras.choices import JournalEntryKindChoices, ObjectChangeActionChoices from extras.choices import JournalEntryKindChoices, ObjectChangeActionChoices
from extras.filters import * from extras.filtersets import *
from extras.models import * from extras.models import *
from ipam.models import IPAddress from ipam.models import IPAddress
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from utilities.testing import BaseFilterSetTests, ChangeLoggedFilterSetTests
from virtualization.models import Cluster, ClusterGroup, ClusterType from virtualization.models import Cluster, ClusterGroup, ClusterType
class WebhookTestCase(TestCase): class WebhookTestCase(TestCase, BaseFilterSetTests):
queryset = Webhook.objects.all() queryset = Webhook.objects.all()
filterset = WebhookFilterSet filterset = WebhookFilterSet
@ -52,10 +54,6 @@ class WebhookTestCase(TestCase):
webhooks[1].content_types.add(content_types[1]) webhooks[1].content_types.add(content_types[1])
webhooks[2].content_types.add(content_types[2]) webhooks[2].content_types.add(content_types[2])
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Webhook 1', 'Webhook 2']} params = {'name': ['Webhook 1', 'Webhook 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -89,7 +87,7 @@ class WebhookTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class CustomLinkTestCase(TestCase): class CustomLinkTestCase(TestCase, BaseFilterSetTests):
queryset = CustomLink.objects.all() queryset = CustomLink.objects.all()
filterset = CustomLinkFilterSet filterset = CustomLinkFilterSet
@ -125,10 +123,6 @@ class CustomLinkTestCase(TestCase):
) )
CustomLink.objects.bulk_create(custom_links) CustomLink.objects.bulk_create(custom_links)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Custom Link 1', 'Custom Link 2']} params = {'name': ['Custom Link 1', 'Custom Link 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -148,7 +142,7 @@ class CustomLinkTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class ExportTemplateTestCase(TestCase): class ExportTemplateTestCase(TestCase, BaseFilterSetTests):
queryset = ExportTemplate.objects.all() queryset = ExportTemplate.objects.all()
filterset = ExportTemplateFilterSet filterset = ExportTemplateFilterSet
@ -164,10 +158,6 @@ class ExportTemplateTestCase(TestCase):
) )
ExportTemplate.objects.bulk_create(export_templates) ExportTemplate.objects.bulk_create(export_templates)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Export Template 1', 'Export Template 2']} params = {'name': ['Export Template 1', 'Export Template 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -177,7 +167,7 @@ class ExportTemplateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class ImageAttachmentTestCase(TestCase): class ImageAttachmentTestCase(TestCase, BaseFilterSetTests):
queryset = ImageAttachment.objects.all() queryset = ImageAttachment.objects.all()
filterset = ImageAttachmentFilterSet filterset = ImageAttachmentFilterSet
@ -235,10 +225,6 @@ class ImageAttachmentTestCase(TestCase):
) )
ImageAttachment.objects.bulk_create(image_attachments) ImageAttachment.objects.bulk_create(image_attachments)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Image Attachment 1', 'Image Attachment 2']} params = {'name': ['Image Attachment 1', 'Image Attachment 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -254,8 +240,14 @@ class ImageAttachmentTestCase(TestCase):
} }
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):
class JournalEntryTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = JournalEntry.objects.all() queryset = JournalEntry.objects.all()
filterset = JournalEntryFilterSet filterset = JournalEntryFilterSet
@ -320,10 +312,6 @@ class JournalEntryTestCase(TestCase):
) )
JournalEntry.objects.bulk_create(journal_entries) JournalEntry.objects.bulk_create(journal_entries)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_created_by(self): def test_created_by(self):
users = User.objects.filter(username__in=['Alice', 'Bob']) users = User.objects.filter(username__in=['Alice', 'Bob'])
params = {'created_by': [users[0].username, users[1].username]} params = {'created_by': [users[0].username, users[1].username]}
@ -348,8 +336,17 @@ class JournalEntryTestCase(TestCase):
params = {'kind': [JournalEntryKindChoices.KIND_INFO, JournalEntryKindChoices.KIND_SUCCESS]} params = {'kind': [JournalEntryKindChoices.KIND_INFO, JournalEntryKindChoices.KIND_SUCCESS]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
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_after': '2020-12-31T00:00:00',
'created_before': '2021-01-02T00:00:00',
}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ConfigContextTestCase(TestCase):
class ConfigContextTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = ConfigContext.objects.all() queryset = ConfigContext.objects.all()
filterset = ConfigContextFilterSet filterset = ConfigContextFilterSet
@ -449,10 +446,6 @@ class ConfigContextTestCase(TestCase):
c.tenant_groups.set([tenant_groups[i]]) c.tenant_groups.set([tenant_groups[i]])
c.tenants.set([tenants[i]]) c.tenants.set([tenants[i]])
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Config Context 1', 'Config Context 2']} params = {'name': ['Config Context 1', 'Config Context 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -530,7 +523,7 @@ class ConfigContextTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class TagTestCase(TestCase): class TagTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Tag.objects.all() queryset = Tag.objects.all()
filterset = TagFilterSet filterset = TagFilterSet
@ -544,10 +537,6 @@ class TagTestCase(TestCase):
) )
Tag.objects.bulk_create(tags) Tag.objects.bulk_create(tags)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Tag 1', 'Tag 2']} params = {'name': ['Tag 1', 'Tag 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -561,7 +550,7 @@ class TagTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ObjectChangeTestCase(TestCase): class ObjectChangeTestCase(TestCase, BaseFilterSetTests):
queryset = ObjectChange.objects.all() queryset = ObjectChange.objects.all()
filterset = ObjectChangeFilterSet filterset = ObjectChangeFilterSet
@ -635,10 +624,6 @@ class ObjectChangeTestCase(TestCase):
) )
ObjectChange.objects.bulk_create(object_changes) ObjectChange.objects.bulk_create(object_changes)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:3]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
def test_user(self): def test_user(self):
params = {'user_id': User.objects.filter(username__in=['user1', 'user2']).values_list('pk', flat=True)} params = {'user_id': User.objects.filter(username__in=['user1', 'user2']).values_list('pk', flat=True)}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)

View File

@ -13,7 +13,7 @@ from utilities.forms import ConfirmationForm
from utilities.tables import paginate_table from utilities.tables import paginate_table
from utilities.utils import copy_safe_request, count_related, shallow_compare_dict from utilities.utils import copy_safe_request, count_related, shallow_compare_dict
from utilities.views import ContentTypePermissionRequiredMixin from utilities.views import ContentTypePermissionRequiredMixin
from . import filters, forms, tables from . import filtersets, forms, tables
from .choices import JobResultStatusChoices from .choices import JobResultStatusChoices
from .models import ConfigContext, ImageAttachment, JournalEntry, ObjectChange, JobResult, Tag, TaggedItem from .models import ConfigContext, ImageAttachment, JournalEntry, ObjectChange, JobResult, Tag, TaggedItem
from .reports import get_report, get_reports, run_report from .reports import get_report, get_reports, run_report
@ -28,7 +28,7 @@ class TagListView(generic.ObjectListView):
queryset = Tag.objects.annotate( queryset = Tag.objects.annotate(
items=count_related(TaggedItem, 'tag') items=count_related(TaggedItem, 'tag')
) )
filterset = filters.TagFilterSet filterset = filtersets.TagFilterSet
filterset_form = forms.TagFilterForm filterset_form = forms.TagFilterForm
table = tables.TagTable table = tables.TagTable
@ -94,7 +94,7 @@ class TagBulkDeleteView(generic.BulkDeleteView):
class ConfigContextListView(generic.ObjectListView): class ConfigContextListView(generic.ObjectListView):
queryset = ConfigContext.objects.all() queryset = ConfigContext.objects.all()
filterset = filters.ConfigContextFilterSet filterset = filtersets.ConfigContextFilterSet
filterset_form = forms.ConfigContextFilterForm filterset_form = forms.ConfigContextFilterForm
table = tables.ConfigContextTable table = tables.ConfigContextTable
action_buttons = ('add',) action_buttons = ('add',)
@ -127,7 +127,7 @@ class ConfigContextEditView(generic.ObjectEditView):
class ConfigContextBulkEditView(generic.BulkEditView): class ConfigContextBulkEditView(generic.BulkEditView):
queryset = ConfigContext.objects.all() queryset = ConfigContext.objects.all()
filterset = filters.ConfigContextFilterSet filterset = filtersets.ConfigContextFilterSet
table = tables.ConfigContextTable table = tables.ConfigContextTable
form = forms.ConfigContextBulkEditForm form = forms.ConfigContextBulkEditForm
@ -173,7 +173,7 @@ class ObjectConfigContextView(generic.ObjectView):
class ObjectChangeListView(generic.ObjectListView): class ObjectChangeListView(generic.ObjectListView):
queryset = ObjectChange.objects.all() queryset = ObjectChange.objects.all()
filterset = filters.ObjectChangeFilterSet filterset = filtersets.ObjectChangeFilterSet
filterset_form = forms.ObjectChangeFilterForm filterset_form = forms.ObjectChangeFilterForm
table = tables.ObjectChangeTable table = tables.ObjectChangeTable
template_name = 'extras/objectchange_list.html' template_name = 'extras/objectchange_list.html'
@ -300,7 +300,7 @@ class ImageAttachmentDeleteView(generic.ObjectDeleteView):
class JournalEntryListView(generic.ObjectListView): class JournalEntryListView(generic.ObjectListView):
queryset = JournalEntry.objects.all() queryset = JournalEntry.objects.all()
filterset = filters.JournalEntryFilterSet filterset = filtersets.JournalEntryFilterSet
filterset_form = forms.JournalEntryFilterForm filterset_form = forms.JournalEntryFilterForm
table = tables.JournalEntryTable table = tables.JournalEntryTable
action_buttons = ('export',) action_buttons = ('export',)
@ -338,14 +338,14 @@ class JournalEntryDeleteView(generic.ObjectDeleteView):
class JournalEntryBulkEditView(generic.BulkEditView): class JournalEntryBulkEditView(generic.BulkEditView):
queryset = JournalEntry.objects.prefetch_related('created_by') queryset = JournalEntry.objects.prefetch_related('created_by')
filterset = filters.JournalEntryFilterSet filterset = filtersets.JournalEntryFilterSet
table = tables.JournalEntryTable table = tables.JournalEntryTable
form = forms.JournalEntryBulkEditForm form = forms.JournalEntryBulkEditForm
class JournalEntryBulkDeleteView(generic.BulkDeleteView): class JournalEntryBulkDeleteView(generic.BulkDeleteView):
queryset = JournalEntry.objects.prefetch_related('created_by') queryset = JournalEntry.objects.prefetch_related('created_by')
filterset = filters.JournalEntryFilterSet filterset = filtersets.JournalEntryFilterSet
table = tables.JournalEntryTable table = tables.JournalEntryTable

View File

@ -10,7 +10,7 @@ from rest_framework.response import Response
from rest_framework.routers import APIRootView from rest_framework.routers import APIRootView
from extras.api.views import CustomFieldModelViewSet from extras.api.views import CustomFieldModelViewSet
from ipam import filters from ipam import filtersets
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF
from netbox.api.views import ModelViewSet from netbox.api.views import ModelViewSet
from utilities.constants import ADVISORY_LOCK_KEYS from utilities.constants import ADVISORY_LOCK_KEYS
@ -38,7 +38,7 @@ class VRFViewSet(CustomFieldModelViewSet):
prefix_count=count_related(Prefix, 'vrf') prefix_count=count_related(Prefix, 'vrf')
) )
serializer_class = serializers.VRFSerializer serializer_class = serializers.VRFSerializer
filterset_class = filters.VRFFilterSet filterset_class = filtersets.VRFFilterSet
# #
@ -48,7 +48,7 @@ class VRFViewSet(CustomFieldModelViewSet):
class RouteTargetViewSet(CustomFieldModelViewSet): class RouteTargetViewSet(CustomFieldModelViewSet):
queryset = RouteTarget.objects.prefetch_related('tenant').prefetch_related('tags') queryset = RouteTarget.objects.prefetch_related('tenant').prefetch_related('tags')
serializer_class = serializers.RouteTargetSerializer serializer_class = serializers.RouteTargetSerializer
filterset_class = filters.RouteTargetFilterSet filterset_class = filtersets.RouteTargetFilterSet
# #
@ -60,7 +60,7 @@ class RIRViewSet(CustomFieldModelViewSet):
aggregate_count=count_related(Aggregate, 'rir') aggregate_count=count_related(Aggregate, 'rir')
) )
serializer_class = serializers.RIRSerializer serializer_class = serializers.RIRSerializer
filterset_class = filters.RIRFilterSet filterset_class = filtersets.RIRFilterSet
# #
@ -70,7 +70,7 @@ class RIRViewSet(CustomFieldModelViewSet):
class AggregateViewSet(CustomFieldModelViewSet): class AggregateViewSet(CustomFieldModelViewSet):
queryset = Aggregate.objects.prefetch_related('rir').prefetch_related('tags') queryset = Aggregate.objects.prefetch_related('rir').prefetch_related('tags')
serializer_class = serializers.AggregateSerializer serializer_class = serializers.AggregateSerializer
filterset_class = filters.AggregateFilterSet filterset_class = filtersets.AggregateFilterSet
# #
@ -83,7 +83,7 @@ class RoleViewSet(CustomFieldModelViewSet):
vlan_count=count_related(VLAN, 'role') vlan_count=count_related(VLAN, 'role')
) )
serializer_class = serializers.RoleSerializer serializer_class = serializers.RoleSerializer
filterset_class = filters.RoleFilterSet filterset_class = filtersets.RoleFilterSet
# #
@ -95,7 +95,7 @@ class PrefixViewSet(CustomFieldModelViewSet):
'site', 'vrf__tenant', 'tenant', 'vlan', 'role', 'tags' 'site', 'vrf__tenant', 'tenant', 'vlan', 'role', 'tags'
) )
serializer_class = serializers.PrefixSerializer serializer_class = serializers.PrefixSerializer
filterset_class = filters.PrefixFilterSet filterset_class = filtersets.PrefixFilterSet
def get_serializer_class(self): def get_serializer_class(self):
if self.action == "available_prefixes" and self.request.method == "POST": if self.action == "available_prefixes" and self.request.method == "POST":
@ -275,7 +275,7 @@ class IPAddressViewSet(CustomFieldModelViewSet):
'vrf__tenant', 'tenant', 'nat_inside', 'nat_outside', 'tags', 'assigned_object' 'vrf__tenant', 'tenant', 'nat_inside', 'nat_outside', 'tags', 'assigned_object'
) )
serializer_class = serializers.IPAddressSerializer serializer_class = serializers.IPAddressSerializer
filterset_class = filters.IPAddressFilterSet filterset_class = filtersets.IPAddressFilterSet
# #
@ -287,7 +287,7 @@ class VLANGroupViewSet(CustomFieldModelViewSet):
vlan_count=count_related(VLAN, 'group') vlan_count=count_related(VLAN, 'group')
) )
serializer_class = serializers.VLANGroupSerializer serializer_class = serializers.VLANGroupSerializer
filterset_class = filters.VLANGroupFilterSet filterset_class = filtersets.VLANGroupFilterSet
# #
@ -301,7 +301,7 @@ class VLANViewSet(CustomFieldModelViewSet):
prefix_count=count_related(Prefix, 'vlan') prefix_count=count_related(Prefix, 'vlan')
) )
serializer_class = serializers.VLANSerializer serializer_class = serializers.VLANSerializer
filterset_class = filters.VLANFilterSet filterset_class = filtersets.VLANFilterSet
# #
@ -313,4 +313,4 @@ class ServiceViewSet(ModelViewSet):
'device', 'virtual_machine', 'tags', 'ipaddresses' 'device', 'virtual_machine', 'tags', 'ipaddresses'
) )
serializer_class = serializers.ServiceSerializer serializer_class = serializers.ServiceSerializer
filterset_class = filters.ServiceFilterSet filterset_class = filtersets.ServiceFilterSet

View File

@ -6,11 +6,11 @@ from django.db.models import Q
from netaddr.core import AddrFormatError from netaddr.core import AddrFormatError
from dcim.models import Device, Interface, Region, Site, SiteGroup from dcim.models import Device, Interface, Region, Site, SiteGroup
from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from extras.filters import TagFilter
from tenancy.filters import TenancyFilterSet from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet
from tenancy.filtersets import TenancyFilterSet
from utilities.filters import ( from utilities.filters import (
BaseFilterSet, ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NameSlugSearchFilterSet, ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, NumericArrayFilter, TreeNodeMultipleChoiceFilter,
NumericArrayFilter, TagFilter, TreeNodeMultipleChoiceFilter,
) )
from virtualization.models import VirtualMachine, VMInterface from virtualization.models import VirtualMachine, VMInterface
from .choices import * from .choices import *
@ -31,7 +31,7 @@ __all__ = (
) )
class VRFFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class VRFFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -74,7 +74,7 @@ class VRFFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, C
fields = ['id', 'name', 'rd', 'enforce_unique'] fields = ['id', 'name', 'rd', 'enforce_unique']
class RouteTargetFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class RouteTargetFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -116,14 +116,14 @@ class RouteTargetFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilt
fields = ['id', 'name'] fields = ['id', 'name']
class RIRFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): 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(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class AggregateFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -173,7 +173,7 @@ class AggregateFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilter
return queryset.none() return queryset.none()
class RoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class RoleFilterSet(OrganizationalModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -184,7 +184,7 @@ class RoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilter
fields = ['id', 'name', 'slug'] fields = ['id', 'name', 'slug']
class PrefixFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class PrefixFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -369,7 +369,7 @@ class PrefixFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet
) )
class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -535,7 +535,7 @@ class IPAddressFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilter
return queryset.exclude(assigned_object_id__isnull=value) return queryset.exclude(assigned_object_id__isnull=value)
class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class VLANGroupFilterSet(OrganizationalModelFilterSet):
scope_type = ContentTypeFilter() scope_type = ContentTypeFilter()
region = django_filters.NumberFilter( region = django_filters.NumberFilter(
method='filter_scope' method='filter_scope'
@ -570,7 +570,7 @@ class VLANGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedF
) )
class VLANFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class VLANFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -666,7 +666,7 @@ class VLANFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet,
return queryset.get_for_virtualmachine(value) return queryset.get_for_virtualmachine(value)
class ServiceFilterSet(BaseFilterSet, CreatedUpdatedFilterSet): class ServiceFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',

View File

@ -2,13 +2,14 @@ from django.test import TestCase
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 *
from ipam.filters import * from ipam.filtersets import *
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF
from utilities.testing import ChangeLoggedFilterSetTests
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
class VRFTestCase(TestCase): class VRFTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VRF.objects.all() queryset = VRF.objects.all()
filterset = VRFFilterSet filterset = VRFFilterSet
@ -53,10 +54,6 @@ class VRFTestCase(TestCase):
vrfs[2].import_targets.add(route_targets[2]) vrfs[2].import_targets.add(route_targets[2])
vrfs[2].export_targets.add(route_targets[2]) vrfs[2].export_targets.add(route_targets[2])
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['VRF 1', 'VRF 2']} params = {'name': ['VRF 1', 'VRF 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -100,7 +97,7 @@ class VRFTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
class RouteTargetTestCase(TestCase): class RouteTargetTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = RouteTarget.objects.all() queryset = RouteTarget.objects.all()
filterset = RouteTargetFilterSet filterset = RouteTargetFilterSet
@ -149,10 +146,6 @@ class RouteTargetTestCase(TestCase):
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])
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['65000:1001', '65000:1002', '65000:1003']} params = {'name': ['65000:1001', '65000:1002', '65000:1003']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
@ -186,7 +179,7 @@ class RouteTargetTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 8) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 8)
class RIRTestCase(TestCase): class RIRTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = RIR.objects.all() queryset = RIR.objects.all()
filterset = RIRFilterSet filterset = RIRFilterSet
@ -203,10 +196,6 @@ class RIRTestCase(TestCase):
) )
RIR.objects.bulk_create(rirs) RIR.objects.bulk_create(rirs)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['RIR 1', 'RIR 2']} params = {'name': ['RIR 1', 'RIR 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -226,7 +215,7 @@ class RIRTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
class AggregateTestCase(TestCase): class AggregateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Aggregate.objects.all() queryset = Aggregate.objects.all()
filterset = AggregateFilterSet filterset = AggregateFilterSet
@ -265,10 +254,6 @@ class AggregateTestCase(TestCase):
) )
Aggregate.objects.bulk_create(aggregates) Aggregate.objects.bulk_create(aggregates)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_family(self): def test_family(self):
params = {'family': '4'} params = {'family': '4'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
@ -304,7 +289,7 @@ class AggregateTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
class RoleTestCase(TestCase): class RoleTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Role.objects.all() queryset = Role.objects.all()
filterset = RoleFilterSet filterset = RoleFilterSet
@ -318,10 +303,6 @@ class RoleTestCase(TestCase):
) )
Role.objects.bulk_create(roles) Role.objects.bulk_create(roles)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Role 1', 'Role 2']} params = {'name': ['Role 1', 'Role 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -331,7 +312,7 @@ class RoleTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class PrefixTestCase(TestCase): class PrefixTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Prefix.objects.all() queryset = Prefix.objects.all()
filterset = PrefixFilterSet filterset = PrefixFilterSet
@ -421,10 +402,6 @@ class PrefixTestCase(TestCase):
) )
Prefix.objects.bulk_create(prefixes) Prefix.objects.bulk_create(prefixes)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_family(self): def test_family(self):
params = {'family': '6'} params = {'family': '6'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 5) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 5)
@ -528,7 +505,7 @@ class PrefixTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
class IPAddressTestCase(TestCase): class IPAddressTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = IPAddress.objects.all() queryset = IPAddress.objects.all()
filterset = IPAddressFilterSet filterset = IPAddressFilterSet
@ -607,10 +584,6 @@ class IPAddressTestCase(TestCase):
) )
IPAddress.objects.bulk_create(ipaddresses) IPAddress.objects.bulk_create(ipaddresses)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_family(self): def test_family(self):
params = {'family': '6'} params = {'family': '6'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 5) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 5)
@ -708,7 +681,7 @@ class IPAddressTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
class VLANGroupTestCase(TestCase): class VLANGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VLANGroup.objects.all() queryset = VLANGroup.objects.all()
filterset = VLANGroupFilterSet filterset = VLANGroupFilterSet
@ -751,10 +724,6 @@ class VLANGroupTestCase(TestCase):
) )
VLANGroup.objects.bulk_create(vlan_groups) VLANGroup.objects.bulk_create(vlan_groups)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['VLAN Group 1', 'VLAN Group 2']} params = {'name': ['VLAN Group 1', 'VLAN Group 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -796,7 +765,7 @@ class VLANGroupTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
class VLANTestCase(TestCase): class VLANTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VLAN.objects.all() queryset = VLAN.objects.all()
filterset = VLANFilterSet filterset = VLANFilterSet
@ -965,10 +934,6 @@ class VLANTestCase(TestCase):
) )
VLAN.objects.bulk_create(vlans) VLAN.objects.bulk_create(vlans)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['VLAN 101', 'VLAN 102']} params = {'name': ['VLAN 101', 'VLAN 102']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -1041,7 +1006,7 @@ class VLANTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) # 5 scoped + 1 global self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6) # 5 scoped + 1 global
class ServiceTestCase(TestCase): class ServiceTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Service.objects.all() queryset = Service.objects.all()
filterset = ServiceFilterSet filterset = ServiceFilterSet
@ -1080,10 +1045,6 @@ class ServiceTestCase(TestCase):
) )
Service.objects.bulk_create(services) Service.objects.bulk_create(services)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:3]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
def test_name(self): def test_name(self):
params = {'name': ['Service 1', 'Service 2']} params = {'name': ['Service 1', 'Service 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -7,7 +7,7 @@ from netbox.views import generic
from utilities.tables import paginate_table from utilities.tables import paginate_table
from utilities.utils import count_related from utilities.utils import count_related
from virtualization.models import VirtualMachine, VMInterface from virtualization.models import VirtualMachine, VMInterface
from . import filters, forms, tables from . import filtersets, forms, tables
from .constants import * from .constants import *
from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF from .models import Aggregate, IPAddress, Prefix, RIR, Role, RouteTarget, Service, VLAN, VLANGroup, VRF
from .utils import add_available_ipaddresses, add_available_prefixes, add_available_vlans from .utils import add_available_ipaddresses, add_available_prefixes, add_available_vlans
@ -19,7 +19,7 @@ from .utils import add_available_ipaddresses, add_available_prefixes, add_availa
class VRFListView(generic.ObjectListView): class VRFListView(generic.ObjectListView):
queryset = VRF.objects.all() queryset = VRF.objects.all()
filterset = filters.VRFFilterSet filterset = filtersets.VRFFilterSet
filterset_form = forms.VRFFilterForm filterset_form = forms.VRFFilterForm
table = tables.VRFTable table = tables.VRFTable
@ -65,14 +65,14 @@ class VRFBulkImportView(generic.BulkImportView):
class VRFBulkEditView(generic.BulkEditView): class VRFBulkEditView(generic.BulkEditView):
queryset = VRF.objects.prefetch_related('tenant') queryset = VRF.objects.prefetch_related('tenant')
filterset = filters.VRFFilterSet filterset = filtersets.VRFFilterSet
table = tables.VRFTable table = tables.VRFTable
form = forms.VRFBulkEditForm form = forms.VRFBulkEditForm
class VRFBulkDeleteView(generic.BulkDeleteView): class VRFBulkDeleteView(generic.BulkDeleteView):
queryset = VRF.objects.prefetch_related('tenant') queryset = VRF.objects.prefetch_related('tenant')
filterset = filters.VRFFilterSet filterset = filtersets.VRFFilterSet
table = tables.VRFTable table = tables.VRFTable
@ -82,7 +82,7 @@ class VRFBulkDeleteView(generic.BulkDeleteView):
class RouteTargetListView(generic.ObjectListView): class RouteTargetListView(generic.ObjectListView):
queryset = RouteTarget.objects.all() queryset = RouteTarget.objects.all()
filterset = filters.RouteTargetFilterSet filterset = filtersets.RouteTargetFilterSet
filterset_form = forms.RouteTargetFilterForm filterset_form = forms.RouteTargetFilterForm
table = tables.RouteTargetTable table = tables.RouteTargetTable
@ -123,14 +123,14 @@ class RouteTargetBulkImportView(generic.BulkImportView):
class RouteTargetBulkEditView(generic.BulkEditView): class RouteTargetBulkEditView(generic.BulkEditView):
queryset = RouteTarget.objects.prefetch_related('tenant') queryset = RouteTarget.objects.prefetch_related('tenant')
filterset = filters.RouteTargetFilterSet filterset = filtersets.RouteTargetFilterSet
table = tables.RouteTargetTable table = tables.RouteTargetTable
form = forms.RouteTargetBulkEditForm form = forms.RouteTargetBulkEditForm
class RouteTargetBulkDeleteView(generic.BulkDeleteView): class RouteTargetBulkDeleteView(generic.BulkDeleteView):
queryset = RouteTarget.objects.prefetch_related('tenant') queryset = RouteTarget.objects.prefetch_related('tenant')
filterset = filters.RouteTargetFilterSet filterset = filtersets.RouteTargetFilterSet
table = tables.RouteTargetTable table = tables.RouteTargetTable
@ -142,7 +142,7 @@ class RIRListView(generic.ObjectListView):
queryset = RIR.objects.annotate( queryset = RIR.objects.annotate(
aggregate_count=count_related(Aggregate, 'rir') aggregate_count=count_related(Aggregate, 'rir')
) )
filterset = filters.RIRFilterSet filterset = filtersets.RIRFilterSet
filterset_form = forms.RIRFilterForm filterset_form = forms.RIRFilterForm
table = tables.RIRTable table = tables.RIRTable
template_name = 'ipam/rir_list.html' template_name = 'ipam/rir_list.html'
@ -184,7 +184,7 @@ class RIRBulkEditView(generic.BulkEditView):
queryset = RIR.objects.annotate( queryset = RIR.objects.annotate(
aggregate_count=count_related(Aggregate, 'rir') aggregate_count=count_related(Aggregate, 'rir')
) )
filterset = filters.RIRFilterSet filterset = filtersets.RIRFilterSet
table = tables.RIRTable table = tables.RIRTable
form = forms.RIRBulkEditForm form = forms.RIRBulkEditForm
@ -193,7 +193,7 @@ class RIRBulkDeleteView(generic.BulkDeleteView):
queryset = RIR.objects.annotate( queryset = RIR.objects.annotate(
aggregate_count=count_related(Aggregate, 'rir') aggregate_count=count_related(Aggregate, 'rir')
) )
filterset = filters.RIRFilterSet filterset = filtersets.RIRFilterSet
table = tables.RIRTable table = tables.RIRTable
@ -205,7 +205,7 @@ class AggregateListView(generic.ObjectListView):
queryset = Aggregate.objects.annotate( queryset = Aggregate.objects.annotate(
child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ()) child_count=RawSQL('SELECT COUNT(*) FROM ipam_prefix WHERE ipam_prefix.prefix <<= ipam_aggregate.prefix', ())
) )
filterset = filters.AggregateFilterSet filterset = filtersets.AggregateFilterSet
filterset_form = forms.AggregateFilterForm filterset_form = forms.AggregateFilterForm
table = tables.AggregateDetailTable table = tables.AggregateDetailTable
template_name = 'ipam/aggregate_list.html' template_name = 'ipam/aggregate_list.html'
@ -280,14 +280,14 @@ class AggregateBulkImportView(generic.BulkImportView):
class AggregateBulkEditView(generic.BulkEditView): class AggregateBulkEditView(generic.BulkEditView):
queryset = Aggregate.objects.prefetch_related('rir') queryset = Aggregate.objects.prefetch_related('rir')
filterset = filters.AggregateFilterSet filterset = filtersets.AggregateFilterSet
table = tables.AggregateTable table = tables.AggregateTable
form = forms.AggregateBulkEditForm form = forms.AggregateBulkEditForm
class AggregateBulkDeleteView(generic.BulkDeleteView): class AggregateBulkDeleteView(generic.BulkDeleteView):
queryset = Aggregate.objects.prefetch_related('rir') queryset = Aggregate.objects.prefetch_related('rir')
filterset = filters.AggregateFilterSet filterset = filtersets.AggregateFilterSet
table = tables.AggregateTable table = tables.AggregateTable
@ -337,7 +337,7 @@ class RoleBulkImportView(generic.BulkImportView):
class RoleBulkEditView(generic.BulkEditView): class RoleBulkEditView(generic.BulkEditView):
queryset = Role.objects.all() queryset = Role.objects.all()
filterset = filters.RoleFilterSet filterset = filtersets.RoleFilterSet
table = tables.RoleTable table = tables.RoleTable
form = forms.RoleBulkEditForm form = forms.RoleBulkEditForm
@ -353,7 +353,7 @@ class RoleBulkDeleteView(generic.BulkDeleteView):
class PrefixListView(generic.ObjectListView): class PrefixListView(generic.ObjectListView):
queryset = Prefix.objects.annotate_tree() queryset = Prefix.objects.annotate_tree()
filterset = filters.PrefixFilterSet filterset = filtersets.PrefixFilterSet
filterset_form = forms.PrefixFilterForm filterset_form = forms.PrefixFilterForm
table = tables.PrefixDetailTable table = tables.PrefixDetailTable
template_name = 'ipam/prefix_list.html' template_name = 'ipam/prefix_list.html'
@ -493,14 +493,14 @@ class PrefixBulkImportView(generic.BulkImportView):
class PrefixBulkEditView(generic.BulkEditView): class PrefixBulkEditView(generic.BulkEditView):
queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role') queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
filterset = filters.PrefixFilterSet filterset = filtersets.PrefixFilterSet
table = tables.PrefixTable table = tables.PrefixTable
form = forms.PrefixBulkEditForm form = forms.PrefixBulkEditForm
class PrefixBulkDeleteView(generic.BulkDeleteView): class PrefixBulkDeleteView(generic.BulkDeleteView):
queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role') queryset = Prefix.objects.prefetch_related('site', 'vrf__tenant', 'tenant', 'vlan', 'role')
filterset = filters.PrefixFilterSet filterset = filtersets.PrefixFilterSet
table = tables.PrefixTable table = tables.PrefixTable
@ -510,7 +510,7 @@ class PrefixBulkDeleteView(generic.BulkDeleteView):
class IPAddressListView(generic.ObjectListView): class IPAddressListView(generic.ObjectListView):
queryset = IPAddress.objects.all() queryset = IPAddress.objects.all()
filterset = filters.IPAddressFilterSet filterset = filtersets.IPAddressFilterSet
filterset_form = forms.IPAddressFilterForm filterset_form = forms.IPAddressFilterForm
table = tables.IPAddressDetailTable table = tables.IPAddressDetailTable
@ -613,7 +613,7 @@ class IPAddressAssignView(generic.ObjectView):
addresses = self.queryset.prefetch_related('vrf', 'tenant') addresses = self.queryset.prefetch_related('vrf', 'tenant')
# Limit to 100 results # Limit to 100 results
addresses = filters.IPAddressFilterSet(request.POST, addresses).qs[:100] addresses = filtersets.IPAddressFilterSet(request.POST, addresses).qs[:100]
table = tables.IPAddressAssignTable(addresses) table = tables.IPAddressAssignTable(addresses)
return render(request, 'ipam/ipaddress_assign.html', { return render(request, 'ipam/ipaddress_assign.html', {
@ -643,14 +643,14 @@ class IPAddressBulkImportView(generic.BulkImportView):
class IPAddressBulkEditView(generic.BulkEditView): class IPAddressBulkEditView(generic.BulkEditView):
queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant') queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
filterset = filters.IPAddressFilterSet filterset = filtersets.IPAddressFilterSet
table = tables.IPAddressTable table = tables.IPAddressTable
form = forms.IPAddressBulkEditForm form = forms.IPAddressBulkEditForm
class IPAddressBulkDeleteView(generic.BulkDeleteView): class IPAddressBulkDeleteView(generic.BulkDeleteView):
queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant') queryset = IPAddress.objects.prefetch_related('vrf__tenant', 'tenant')
filterset = filters.IPAddressFilterSet filterset = filtersets.IPAddressFilterSet
table = tables.IPAddressTable table = tables.IPAddressTable
@ -662,7 +662,7 @@ class VLANGroupListView(generic.ObjectListView):
queryset = VLANGroup.objects.annotate( queryset = VLANGroup.objects.annotate(
vlan_count=count_related(VLAN, 'group') vlan_count=count_related(VLAN, 'group')
) )
filterset = filters.VLANGroupFilterSet filterset = filtersets.VLANGroupFilterSet
filterset_form = forms.VLANGroupFilterForm filterset_form = forms.VLANGroupFilterForm
table = tables.VLANGroupTable table = tables.VLANGroupTable
@ -673,7 +673,7 @@ class VLANGroupView(generic.ObjectView):
def get_extra_context(self, request, instance): def get_extra_context(self, request, instance):
vlans = VLAN.objects.restrict(request.user, 'view').filter(group=instance).prefetch_related( vlans = VLAN.objects.restrict(request.user, 'view').filter(group=instance).prefetch_related(
Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user)) Prefetch('prefixes', queryset=Prefix.objects.restrict(request.user))
) ).order_by('vid')
vlans_count = vlans.count() vlans_count = vlans.count()
vlans = add_available_vlans(instance, vlans) vlans = add_available_vlans(instance, vlans)
@ -684,9 +684,17 @@ class VLANGroupView(generic.ObjectView):
vlans_table.columns.hide('group') vlans_table.columns.hide('group')
paginate_table(vlans_table, request) paginate_table(vlans_table, request)
# Compile permissions list for rendering the object table
permissions = {
'add': request.user.has_perm('ipam.add_vlan'),
'change': request.user.has_perm('ipam.change_vlan'),
'delete': request.user.has_perm('ipam.delete_vlan'),
}
return { return {
'vlans_count': vlans_count, 'vlans_count': vlans_count,
'vlans_table': vlans_table, 'vlans_table': vlans_table,
'permissions': permissions,
} }
@ -710,7 +718,7 @@ class VLANGroupBulkEditView(generic.BulkEditView):
queryset = VLANGroup.objects.annotate( queryset = VLANGroup.objects.annotate(
vlan_count=count_related(VLAN, 'group') vlan_count=count_related(VLAN, 'group')
) )
filterset = filters.VLANGroupFilterSet filterset = filtersets.VLANGroupFilterSet
table = tables.VLANGroupTable table = tables.VLANGroupTable
form = forms.VLANGroupBulkEditForm form = forms.VLANGroupBulkEditForm
@ -719,7 +727,7 @@ class VLANGroupBulkDeleteView(generic.BulkDeleteView):
queryset = VLANGroup.objects.annotate( queryset = VLANGroup.objects.annotate(
vlan_count=count_related(VLAN, 'group') vlan_count=count_related(VLAN, 'group')
) )
filterset = filters.VLANGroupFilterSet filterset = filtersets.VLANGroupFilterSet
table = tables.VLANGroupTable table = tables.VLANGroupTable
@ -729,7 +737,7 @@ class VLANGroupBulkDeleteView(generic.BulkDeleteView):
class VLANListView(generic.ObjectListView): class VLANListView(generic.ObjectListView):
queryset = VLAN.objects.all() queryset = VLAN.objects.all()
filterset = filters.VLANFilterSet filterset = filtersets.VLANFilterSet
filterset_form = forms.VLANFilterForm filterset_form = forms.VLANFilterForm
table = tables.VLANDetailTable table = tables.VLANDetailTable
@ -797,14 +805,14 @@ class VLANBulkImportView(generic.BulkImportView):
class VLANBulkEditView(generic.BulkEditView): class VLANBulkEditView(generic.BulkEditView):
queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role') queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role')
filterset = filters.VLANFilterSet filterset = filtersets.VLANFilterSet
table = tables.VLANTable table = tables.VLANTable
form = forms.VLANBulkEditForm form = forms.VLANBulkEditForm
class VLANBulkDeleteView(generic.BulkDeleteView): class VLANBulkDeleteView(generic.BulkDeleteView):
queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role') queryset = VLAN.objects.prefetch_related('site', 'group', 'tenant', 'role')
filterset = filters.VLANFilterSet filterset = filtersets.VLANFilterSet
table = tables.VLANTable table = tables.VLANTable
@ -814,7 +822,7 @@ class VLANBulkDeleteView(generic.BulkDeleteView):
class ServiceListView(generic.ObjectListView): class ServiceListView(generic.ObjectListView):
queryset = Service.objects.all() queryset = Service.objects.all()
filterset = filters.ServiceFilterSet filterset = filtersets.ServiceFilterSet
filterset_form = forms.ServiceFilterForm filterset_form = forms.ServiceFilterForm
table = tables.ServiceTable table = tables.ServiceTable
action_buttons = ('import', 'export') action_buttons = ('import', 'export')
@ -855,12 +863,12 @@ class ServiceDeleteView(generic.ObjectDeleteView):
class ServiceBulkEditView(generic.BulkEditView): class ServiceBulkEditView(generic.BulkEditView):
queryset = Service.objects.prefetch_related('device', 'virtual_machine') queryset = Service.objects.prefetch_related('device', 'virtual_machine')
filterset = filters.ServiceFilterSet filterset = filtersets.ServiceFilterSet
table = tables.ServiceTable table = tables.ServiceTable
form = forms.ServiceBulkEditForm form = forms.ServiceBulkEditForm
class ServiceBulkDeleteView(generic.BulkDeleteView): class ServiceBulkDeleteView(generic.BulkDeleteView):
queryset = Service.objects.prefetch_related('device', 'virtual_machine') queryset = Service.objects.prefetch_related('device', 'virtual_machine')
filterset = filters.ServiceFilterSet filterset = filtersets.ServiceFilterSet
table = tables.ServiceTable table = tables.ServiceTable

View File

@ -246,6 +246,9 @@ RQ_DEFAULT_TIMEOUT = 300
# this setting is derived from the installed location. # this setting is derived from the installed location.
# SCRIPTS_ROOT = '/opt/netbox/netbox/scripts' # SCRIPTS_ROOT = '/opt/netbox/netbox/scripts'
# The name to use for the session cookie.
SESSION_COOKIE_NAME = 'sessionid'
# By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use # By default, NetBox will store session data in the database. Alternatively, a file path can be specified here to use
# local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only # local file storage instead. (This can be useful for enabling authentication on a standby instance with read-only
# database access.) Note that the user as which NetBox runs must have read and write permissions to this path. # database access.) Note that the user as which NetBox runs must have read and write permissions to this path.

View File

@ -1,9 +1,9 @@
from collections import OrderedDict from collections import OrderedDict
from circuits.filters import CircuitFilterSet, ProviderFilterSet, ProviderNetworkFilterSet from circuits.filtersets import CircuitFilterSet, ProviderFilterSet, ProviderNetworkFilterSet
from circuits.models import Circuit, ProviderNetwork, Provider from circuits.models import Circuit, ProviderNetwork, Provider
from circuits.tables import CircuitTable, ProviderNetworkTable, ProviderTable from circuits.tables import CircuitTable, ProviderNetworkTable, ProviderTable
from dcim.filters import ( from dcim.filtersets import (
CableFilterSet, DeviceFilterSet, DeviceTypeFilterSet, PowerFeedFilterSet, RackFilterSet, LocationFilterSet, CableFilterSet, DeviceFilterSet, DeviceTypeFilterSet, PowerFeedFilterSet, RackFilterSet, LocationFilterSet,
SiteFilterSet, VirtualChassisFilterSet, SiteFilterSet, VirtualChassisFilterSet,
) )
@ -12,17 +12,17 @@ from dcim.tables import (
CableTable, DeviceTable, DeviceTypeTable, PowerFeedTable, RackTable, LocationTable, SiteTable, CableTable, DeviceTable, DeviceTypeTable, PowerFeedTable, RackTable, LocationTable, SiteTable,
VirtualChassisTable, VirtualChassisTable,
) )
from ipam.filters import AggregateFilterSet, IPAddressFilterSet, PrefixFilterSet, VLANFilterSet, VRFFilterSet from ipam.filtersets import AggregateFilterSet, IPAddressFilterSet, PrefixFilterSet, VLANFilterSet, VRFFilterSet
from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF from ipam.models import Aggregate, IPAddress, Prefix, VLAN, VRF
from ipam.tables import AggregateTable, IPAddressTable, PrefixTable, VLANTable, VRFTable from ipam.tables import AggregateTable, IPAddressTable, PrefixTable, VLANTable, VRFTable
from secrets.filters import SecretFilterSet from secrets.filtersets import SecretFilterSet
from secrets.models import Secret from secrets.models import Secret
from secrets.tables import SecretTable from secrets.tables import SecretTable
from tenancy.filters import TenantFilterSet from tenancy.filtersets import TenantFilterSet
from tenancy.models import Tenant from tenancy.models import Tenant
from tenancy.tables import TenantTable from tenancy.tables import TenantTable
from utilities.utils import count_related from utilities.utils import count_related
from virtualization.filters import ClusterFilterSet, VirtualMachineFilterSet from virtualization.filtersets import ClusterFilterSet, VirtualMachineFilterSet
from virtualization.models import Cluster, VirtualMachine from virtualization.models import Cluster, VirtualMachine
from virtualization.tables import ClusterTable, VirtualMachineDetailTable from virtualization.tables import ClusterTable, VirtualMachineDetailTable

238
netbox/netbox/filtersets.py Normal file
View File

@ -0,0 +1,238 @@
import django_filters
from copy import deepcopy
from django.contrib.contenttypes.models import ContentType
from django.db import models
from django_filters.utils import get_model_field, resolve_field
from dcim.forms import MACAddressField
from extras.choices import CustomFieldFilterLogicChoices
from extras.filters import CustomFieldFilter, TagFilter
from extras.models import CustomField
from utilities.constants import (
FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP,
FILTER_NUMERIC_BASED_LOOKUP_MAP
)
from utilities import filters
__all__ = (
'BaseFilterSet',
'ChangeLoggedModelFilterSet',
'OrganizationalModelFilterSet',
'PrimaryModelFilterSet',
)
#
# FilterSets
#
class BaseFilterSet(django_filters.FilterSet):
"""
A base FilterSet which provides common functionality to all NetBox FilterSets
"""
FILTER_DEFAULTS = deepcopy(django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS)
FILTER_DEFAULTS.update({
models.AutoField: {
'filter_class': filters.MultiValueNumberFilter
},
models.CharField: {
'filter_class': filters.MultiValueCharFilter
},
models.DateField: {
'filter_class': filters.MultiValueDateFilter
},
models.DateTimeField: {
'filter_class': filters.MultiValueDateTimeFilter
},
models.DecimalField: {
'filter_class': filters.MultiValueNumberFilter
},
models.EmailField: {
'filter_class': filters.MultiValueCharFilter
},
models.FloatField: {
'filter_class': filters.MultiValueNumberFilter
},
models.IntegerField: {
'filter_class': filters.MultiValueNumberFilter
},
models.PositiveIntegerField: {
'filter_class': filters.MultiValueNumberFilter
},
models.PositiveSmallIntegerField: {
'filter_class': filters.MultiValueNumberFilter
},
models.SlugField: {
'filter_class': filters.MultiValueCharFilter
},
models.SmallIntegerField: {
'filter_class': filters.MultiValueNumberFilter
},
models.TimeField: {
'filter_class': filters.MultiValueTimeFilter
},
models.URLField: {
'filter_class': filters.MultiValueCharFilter
},
MACAddressField: {
'filter_class': filters.MultiValueMACAddressFilter
},
})
@staticmethod
def _get_filter_lookup_dict(existing_filter):
# Choose the lookup expression map based on the filter type
if isinstance(existing_filter, (
filters.MultiValueDateFilter,
filters.MultiValueDateTimeFilter,
filters.MultiValueNumberFilter,
filters.MultiValueTimeFilter
)):
lookup_map = FILTER_NUMERIC_BASED_LOOKUP_MAP
elif isinstance(existing_filter, (
filters.TreeNodeMultipleChoiceFilter,
)):
# TreeNodeMultipleChoiceFilter only support negation but must maintain the `in` lookup expression
lookup_map = FILTER_TREENODE_NEGATION_LOOKUP_MAP
elif isinstance(existing_filter, (
django_filters.ModelChoiceFilter,
django_filters.ModelMultipleChoiceFilter,
TagFilter
)) or existing_filter.extra.get('choices'):
# These filter types support only negation
lookup_map = FILTER_NEGATION_LOOKUP_MAP
elif isinstance(existing_filter, (
django_filters.filters.CharFilter,
django_filters.MultipleChoiceFilter,
filters.MultiValueCharFilter,
filters.MultiValueMACAddressFilter
)):
lookup_map = FILTER_CHAR_BASED_LOOKUP_MAP
else:
lookup_map = None
return lookup_map
@classmethod
def get_filters(cls):
"""
Override filter generation to support dynamic lookup expressions for certain filter types.
For specific filter types, new filters are created based on defined lookup expressions in
the form `<field_name>__<lookup_expr>`
"""
filters = super().get_filters()
new_filters = {}
for existing_filter_name, existing_filter in filters.items():
# Loop over existing filters to extract metadata by which to create new filters
# If the filter makes use of a custom filter method or lookup expression skip it
# as we cannot sanely handle these cases in a generic mannor
if existing_filter.method is not None or existing_filter.lookup_expr not in ['exact', 'in']:
continue
# Choose the lookup expression map based on the filter type
lookup_map = cls._get_filter_lookup_dict(existing_filter)
if lookup_map is None:
# Do not augment this filter type with more lookup expressions
continue
# Get properties of the existing filter for later use
field_name = existing_filter.field_name
field = get_model_field(cls._meta.model, field_name)
# Create new filters for each lookup expression in the map
for lookup_name, lookup_expr in lookup_map.items():
new_filter_name = '{}__{}'.format(existing_filter_name, lookup_name)
try:
if existing_filter_name in cls.declared_filters:
# The filter field has been explicity defined on the filterset class so we must manually
# create the new filter with the same type because there is no guarantee the defined type
# is the same as the default type for the field
resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid
new_filter = type(existing_filter)(
field_name=field_name,
lookup_expr=lookup_expr,
label=existing_filter.label,
exclude=existing_filter.exclude,
distinct=existing_filter.distinct,
**existing_filter.extra
)
else:
# The filter field is listed in Meta.fields so we can safely rely on default behaviour
# Will raise FieldLookupError if the lookup is invalid
new_filter = cls.filter_for_field(field, field_name, lookup_expr)
except django_filters.exceptions.FieldLookupError:
# The filter could not be created because the lookup expression is not supported on the field
continue
if lookup_name.startswith('n'):
# This is a negation filter which requires a queryset.exclude() clause
# Of course setting the negation of the existing filter's exclude attribute handles both cases
new_filter.exclude = not existing_filter.exclude
new_filters[new_filter_name] = new_filter
filters.update(new_filters)
return filters
class ChangeLoggedModelFilterSet(BaseFilterSet):
created = django_filters.DateFilter()
created__gte = django_filters.DateFilter(
field_name='created',
lookup_expr='gte'
)
created__lte = django_filters.DateFilter(
field_name='created',
lookup_expr='lte'
)
last_updated = django_filters.DateTimeFilter()
last_updated__gte = django_filters.DateTimeFilter(
field_name='last_updated',
lookup_expr='gte'
)
last_updated__lte = django_filters.DateTimeFilter(
field_name='last_updated',
lookup_expr='lte'
)
class PrimaryModelFilterSet(ChangeLoggedModelFilterSet):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Dynamically add a Filter for each CustomField applicable to the parent model
custom_fields = CustomField.objects.filter(
content_types=ContentType.objects.get_for_model(self._meta.model)
).exclude(
filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED
)
for cf in custom_fields:
self.filters['cf_{}'.format(cf.name)] = CustomFieldFilter(field_name=cf.name, custom_field=cf)
class OrganizationalModelFilterSet(PrimaryModelFilterSet):
"""
A base class for adding the search method to models which only expose the `name` and `slug` fields
"""
q = django_filters.CharFilter(
method='search',
label='Search',
)
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
models.Q(name__icontains=value) |
models.Q(slug__icontains=value)
)

View File

@ -114,6 +114,7 @@ REPORTS_ROOT = getattr(configuration, 'REPORTS_ROOT', os.path.join(BASE_DIR, 're
RQ_DEFAULT_TIMEOUT = getattr(configuration, 'RQ_DEFAULT_TIMEOUT', 300) RQ_DEFAULT_TIMEOUT = getattr(configuration, 'RQ_DEFAULT_TIMEOUT', 300)
SCRIPTS_ROOT = getattr(configuration, 'SCRIPTS_ROOT', os.path.join(BASE_DIR, 'scripts')).rstrip('/') SCRIPTS_ROOT = getattr(configuration, 'SCRIPTS_ROOT', os.path.join(BASE_DIR, 'scripts')).rstrip('/')
SESSION_FILE_PATH = getattr(configuration, 'SESSION_FILE_PATH', None) SESSION_FILE_PATH = getattr(configuration, 'SESSION_FILE_PATH', None)
SESSION_COOKIE_NAME = getattr(configuration, 'SESSION_COOKIE_NAME', 'sessionid')
SHORT_DATE_FORMAT = getattr(configuration, 'SHORT_DATE_FORMAT', 'Y-m-d') SHORT_DATE_FORMAT = getattr(configuration, 'SHORT_DATE_FORMAT', 'Y-m-d')
SHORT_DATETIME_FORMAT = getattr(configuration, 'SHORT_DATETIME_FORMAT', 'Y-m-d H:i') SHORT_DATETIME_FORMAT = getattr(configuration, 'SHORT_DATETIME_FORMAT', 'Y-m-d H:i')
SHORT_TIME_FORMAT = getattr(configuration, 'SHORT_TIME_FORMAT', 'H:i:s') SHORT_TIME_FORMAT = getattr(configuration, 'SHORT_TIME_FORMAT', 'H:i:s')

View File

@ -10,7 +10,7 @@ from rest_framework.viewsets import ViewSet
from extras.api.views import CustomFieldModelViewSet from extras.api.views import CustomFieldModelViewSet
from netbox.api.views import ModelViewSet from netbox.api.views import ModelViewSet
from secrets import filters from secrets import filtersets
from secrets.exceptions import InvalidKey from secrets.exceptions import InvalidKey
from secrets.models import Secret, SecretRole, SessionKey, UserKey from secrets.models import Secret, SecretRole, SessionKey, UserKey
from utilities.utils import count_related from utilities.utils import count_related
@ -39,7 +39,7 @@ class SecretRoleViewSet(CustomFieldModelViewSet):
secret_count=count_related(Secret, 'role') secret_count=count_related(Secret, 'role')
) )
serializer_class = serializers.SecretRoleSerializer serializer_class = serializers.SecretRoleSerializer
filterset_class = filters.SecretRoleFilterSet filterset_class = filtersets.SecretRoleFilterSet
# #
@ -49,7 +49,7 @@ class SecretRoleViewSet(CustomFieldModelViewSet):
class SecretViewSet(ModelViewSet): class SecretViewSet(ModelViewSet):
queryset = Secret.objects.prefetch_related('role', 'tags') queryset = Secret.objects.prefetch_related('role', 'tags')
serializer_class = serializers.SecretSerializer serializer_class = serializers.SecretSerializer
filterset_class = filters.SecretFilterSet filterset_class = filtersets.SecretFilterSet
master_key = None master_key = None

View File

@ -2,8 +2,8 @@ import django_filters
from django.db.models import Q from django.db.models import Q
from dcim.models import Device from dcim.models import Device
from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from extras.filters import TagFilter
from utilities.filters import BaseFilterSet, NameSlugSearchFilterSet, TagFilter from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet
from virtualization.models import VirtualMachine from virtualization.models import VirtualMachine
from .models import Secret, SecretRole from .models import Secret, SecretRole
@ -14,14 +14,14 @@ __all__ = (
) )
class SecretRoleFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class SecretRoleFilterSet(OrganizationalModelFilterSet):
class Meta: class Meta:
model = SecretRole model = SecretRole
fields = ['id', 'name', 'slug'] fields = ['id', 'name', 'slug']
class SecretFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class SecretFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',

View File

@ -1,12 +1,13 @@
from django.test import TestCase from django.test import TestCase
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Site
from secrets.filters import * from secrets.filtersets import *
from secrets.models import Secret, SecretRole from secrets.models import Secret, SecretRole
from utilities.testing import ChangeLoggedFilterSetTests
from virtualization.models import Cluster, ClusterType, VirtualMachine from virtualization.models import Cluster, ClusterType, VirtualMachine
class SecretRoleTestCase(TestCase): class SecretRoleTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = SecretRole.objects.all() queryset = SecretRole.objects.all()
filterset = SecretRoleFilterSet filterset = SecretRoleFilterSet
@ -20,10 +21,6 @@ class SecretRoleTestCase(TestCase):
) )
SecretRole.objects.bulk_create(roles) SecretRole.objects.bulk_create(roles)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Secret Role 1', 'Secret Role 2']} params = {'name': ['Secret Role 1', 'Secret Role 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -33,7 +30,7 @@ class SecretRoleTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class SecretTestCase(TestCase): class SecretTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Secret.objects.all() queryset = Secret.objects.all()
filterset = SecretFilterSet filterset = SecretFilterSet
@ -80,10 +77,6 @@ class SecretTestCase(TestCase):
for s in secrets: for s in secrets:
s.save() s.save()
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Secret 1', 'Secret 2']} params = {'name': ['Secret 1', 'Secret 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -2,14 +2,14 @@ import base64
import logging import logging
from django.contrib import messages from django.contrib import messages
from django.shortcuts import get_object_or_404, redirect, render from django.shortcuts import redirect, render
from django.utils.html import escape from django.utils.html import escape
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from netbox.views import generic from netbox.views import generic
from utilities.tables import paginate_table from utilities.tables import paginate_table
from utilities.utils import count_related from utilities.utils import count_related
from . import filters, forms, tables from . import filtersets, forms, tables
from .models import SecretRole, Secret, SessionKey, UserKey from .models import SecretRole, Secret, SessionKey, UserKey
@ -70,7 +70,7 @@ class SecretRoleBulkEditView(generic.BulkEditView):
queryset = SecretRole.objects.annotate( queryset = SecretRole.objects.annotate(
secret_count=count_related(Secret, 'role') secret_count=count_related(Secret, 'role')
) )
filterset = filters.SecretRoleFilterSet filterset = filtersets.SecretRoleFilterSet
table = tables.SecretRoleTable table = tables.SecretRoleTable
form = forms.SecretRoleBulkEditForm form = forms.SecretRoleBulkEditForm
@ -88,7 +88,7 @@ class SecretRoleBulkDeleteView(generic.BulkDeleteView):
class SecretListView(generic.ObjectListView): class SecretListView(generic.ObjectListView):
queryset = Secret.objects.all() queryset = Secret.objects.all()
filterset = filters.SecretFilterSet filterset = filtersets.SecretFilterSet
filterset_form = forms.SecretFilterForm filterset_form = forms.SecretFilterForm
table = tables.SecretTable table = tables.SecretTable
action_buttons = ('add', 'import', 'export') action_buttons = ('add', 'import', 'export')
@ -220,12 +220,12 @@ class SecretBulkImportView(generic.BulkImportView):
class SecretBulkEditView(generic.BulkEditView): class SecretBulkEditView(generic.BulkEditView):
queryset = Secret.objects.prefetch_related('role') queryset = Secret.objects.prefetch_related('role')
filterset = filters.SecretFilterSet filterset = filtersets.SecretFilterSet
table = tables.SecretTable table = tables.SecretTable
form = forms.SecretBulkEditForm form = forms.SecretBulkEditForm
class SecretBulkDeleteView(generic.BulkDeleteView): class SecretBulkDeleteView(generic.BulkDeleteView):
queryset = Secret.objects.prefetch_related('role') queryset = Secret.objects.prefetch_related('role')
filterset = filters.SecretFilterSet filterset = filtersets.SecretFilterSet
table = tables.SecretTable table = tables.SecretTable

View File

@ -10,6 +10,15 @@
<li class="breadcrumb-item">{{ object }}</li> <li class="breadcrumb-item">{{ object }}</li>
{% endblock %} {% endblock %}
{% block buttons %}
{% if perms.ipam.add_vlan %}
<a href="{% url 'ipam:vlan_add' %}?group={{ object.pk }}" class="btn btn-success">
<span class="mdi mdi-plus-thick" aria-hidden="true"></span> Add VLAN
</a>
{% endif %}
{{ block.super }}
{% endblock %}
{% block content %} {% block content %}
<div class="row mb-3"> <div class="row mb-3">
<div class="col col-md-6"> <div class="col col-md-6">

View File

@ -4,7 +4,7 @@ from circuits.models import Circuit
from dcim.models import Device, Rack, Site from dcim.models import Device, Rack, Site
from extras.api.views import CustomFieldModelViewSet from extras.api.views import CustomFieldModelViewSet
from ipam.models import IPAddress, Prefix, VLAN, VRF from ipam.models import IPAddress, Prefix, VLAN, VRF
from tenancy import filters from tenancy import filtersets
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from utilities.utils import count_related from utilities.utils import count_related
from virtualization.models import VirtualMachine from virtualization.models import VirtualMachine
@ -32,7 +32,7 @@ class TenantGroupViewSet(CustomFieldModelViewSet):
cumulative=True cumulative=True
) )
serializer_class = serializers.TenantGroupSerializer serializer_class = serializers.TenantGroupSerializer
filterset_class = filters.TenantGroupFilterSet filterset_class = filtersets.TenantGroupFilterSet
# #
@ -54,4 +54,4 @@ class TenantViewSet(CustomFieldModelViewSet):
vrf_count=count_related(VRF, 'tenant') vrf_count=count_related(VRF, 'tenant')
) )
serializer_class = serializers.TenantSerializer serializer_class = serializers.TenantSerializer
filterset_class = filters.TenantFilterSet filterset_class = filtersets.TenantFilterSet

View File

@ -1,8 +1,9 @@
import django_filters import django_filters
from django.db.models import Q from django.db.models import Q
from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet from extras.filters import TagFilter
from utilities.filters import BaseFilterSet, NameSlugSearchFilterSet, TagFilter, TreeNodeMultipleChoiceFilter from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet
from utilities.filters import TreeNodeMultipleChoiceFilter
from .models import Tenant, TenantGroup from .models import Tenant, TenantGroup
@ -13,7 +14,7 @@ __all__ = (
) )
class TenantGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class TenantGroupFilterSet(OrganizationalModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=TenantGroup.objects.all(), queryset=TenantGroup.objects.all(),
label='Tenant group (ID)', label='Tenant group (ID)',
@ -30,7 +31,7 @@ class TenantGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdate
fields = ['id', 'name', 'slug', 'description'] fields = ['id', 'name', 'slug', 'description']
class TenantFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class TenantFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',

View File

@ -1,10 +1,11 @@
from django.test import TestCase from django.test import TestCase
from tenancy.filters import * from tenancy.filtersets import *
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from utilities.testing import ChangeLoggedFilterSetTests
class TenantGroupTestCase(TestCase): class TenantGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = TenantGroup.objects.all() queryset = TenantGroup.objects.all()
filterset = TenantGroupFilterSet filterset = TenantGroupFilterSet
@ -27,10 +28,6 @@ class TenantGroupTestCase(TestCase):
for tenantgroup in tenant_groups: for tenantgroup in tenant_groups:
tenantgroup.save() tenantgroup.save()
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Tenant Group 1', 'Tenant Group 2']} params = {'name': ['Tenant Group 1', 'Tenant Group 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -51,7 +48,7 @@ class TenantGroupTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class TenantTestCase(TestCase): class TenantTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Tenant.objects.all() queryset = Tenant.objects.all()
filterset = TenantFilterSet filterset = TenantFilterSet
@ -73,10 +70,6 @@ class TenantTestCase(TestCase):
) )
Tenant.objects.bulk_create(tenants) Tenant.objects.bulk_create(tenants)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Tenant 1', 'Tenant 2']} params = {'name': ['Tenant 1', 'Tenant 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -4,7 +4,7 @@ from ipam.models import IPAddress, Prefix, VLAN, VRF
from netbox.views import generic from netbox.views import generic
from utilities.tables import paginate_table from utilities.tables import paginate_table
from virtualization.models import VirtualMachine, Cluster from virtualization.models import VirtualMachine, Cluster
from . import filters, forms, tables from . import filtersets, forms, tables
from .models import Tenant, TenantGroup from .models import Tenant, TenantGroup
@ -63,7 +63,7 @@ class TenantGroupBulkEditView(generic.BulkEditView):
'tenant_count', 'tenant_count',
cumulative=True cumulative=True
) )
filterset = filters.TenantGroupFilterSet filterset = filtersets.TenantGroupFilterSet
table = tables.TenantGroupTable table = tables.TenantGroupTable
form = forms.TenantGroupBulkEditForm form = forms.TenantGroupBulkEditForm
@ -85,7 +85,7 @@ class TenantGroupBulkDeleteView(generic.BulkDeleteView):
class TenantListView(generic.ObjectListView): class TenantListView(generic.ObjectListView):
queryset = Tenant.objects.all() queryset = Tenant.objects.all()
filterset = filters.TenantFilterSet filterset = filtersets.TenantFilterSet
filterset_form = forms.TenantFilterForm filterset_form = forms.TenantFilterForm
table = tables.TenantTable table = tables.TenantTable
@ -130,12 +130,12 @@ class TenantBulkImportView(generic.BulkImportView):
class TenantBulkEditView(generic.BulkEditView): class TenantBulkEditView(generic.BulkEditView):
queryset = Tenant.objects.prefetch_related('group') queryset = Tenant.objects.prefetch_related('group')
filterset = filters.TenantFilterSet filterset = filtersets.TenantFilterSet
table = tables.TenantTable table = tables.TenantTable
form = forms.TenantBulkEditForm form = forms.TenantBulkEditForm
class TenantBulkDeleteView(generic.BulkDeleteView): class TenantBulkDeleteView(generic.BulkDeleteView):
queryset = Tenant.objects.prefetch_related('group') queryset = Tenant.objects.prefetch_related('group')
filterset = filters.TenantFilterSet filterset = filtersets.TenantFilterSet
table = tables.TenantTable table = tables.TenantTable

View File

@ -6,7 +6,7 @@ from rest_framework.routers import APIRootView
from rest_framework.viewsets import ViewSet from rest_framework.viewsets import ViewSet
from netbox.api.views import ModelViewSet from netbox.api.views import ModelViewSet
from users import filters from users import filtersets
from users.models import ObjectPermission, UserConfig from users.models import ObjectPermission, UserConfig
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
from utilities.utils import deepmerge from utilities.utils import deepmerge
@ -28,13 +28,13 @@ class UsersRootView(APIRootView):
class UserViewSet(ModelViewSet): class UserViewSet(ModelViewSet):
queryset = RestrictedQuerySet(model=User).prefetch_related('groups').order_by('username') queryset = RestrictedQuerySet(model=User).prefetch_related('groups').order_by('username')
serializer_class = serializers.UserSerializer serializer_class = serializers.UserSerializer
filterset_class = filters.UserFilterSet filterset_class = filtersets.UserFilterSet
class GroupViewSet(ModelViewSet): class GroupViewSet(ModelViewSet):
queryset = RestrictedQuerySet(model=Group).annotate(user_count=Count('user')).order_by('name') queryset = RestrictedQuerySet(model=Group).annotate(user_count=Count('user')).order_by('name')
serializer_class = serializers.GroupSerializer serializer_class = serializers.GroupSerializer
filterset_class = filters.GroupFilterSet filterset_class = filtersets.GroupFilterSet
# #
@ -44,7 +44,7 @@ class GroupViewSet(ModelViewSet):
class ObjectPermissionViewSet(ModelViewSet): class ObjectPermissionViewSet(ModelViewSet):
queryset = ObjectPermission.objects.prefetch_related('object_types', 'groups', 'users') queryset = ObjectPermission.objects.prefetch_related('object_types', 'groups', 'users')
serializer_class = serializers.ObjectPermissionSerializer serializer_class = serializers.ObjectPermissionSerializer
filterset_class = filters.ObjectPermissionFilterSet filterset_class = filtersets.ObjectPermissionFilterSet
# #

View File

@ -2,8 +2,8 @@ import django_filters
from django.contrib.auth.models import Group, User from django.contrib.auth.models import Group, User
from django.db.models import Q from django.db.models import Q
from netbox.filtersets import BaseFilterSet
from users.models import ObjectPermission from users.models import ObjectPermission
from utilities.filters import BaseFilterSet
__all__ = ( __all__ = (
'GroupFilterSet', 'GroupFilterSet',

View File

@ -2,11 +2,12 @@ from django.contrib.auth.models import Group, User
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.test import TestCase from django.test import TestCase
from users.filters import GroupFilterSet, ObjectPermissionFilterSet, UserFilterSet from users.filtersets import GroupFilterSet, ObjectPermissionFilterSet, UserFilterSet
from users.models import ObjectPermission from users.models import ObjectPermission
from utilities.testing import BaseFilterSetTests
class UserTestCase(TestCase): class UserTestCase(TestCase, BaseFilterSetTests):
queryset = User.objects.all() queryset = User.objects.all()
filterset = UserFilterSet filterset = UserFilterSet
@ -59,10 +60,6 @@ class UserTestCase(TestCase):
users[1].groups.set([groups[1]]) users[1].groups.set([groups[1]])
users[2].groups.set([groups[2]]) users[2].groups.set([groups[2]])
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_username(self): def test_username(self):
params = {'username': ['User1', 'User2']} params = {'username': ['User1', 'User2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -95,7 +92,7 @@ class UserTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class GroupTestCase(TestCase): class GroupTestCase(TestCase, BaseFilterSetTests):
queryset = Group.objects.all() queryset = Group.objects.all()
filterset = GroupFilterSet filterset = GroupFilterSet
@ -109,16 +106,12 @@ class GroupTestCase(TestCase):
) )
Group.objects.bulk_create(groups) Group.objects.bulk_create(groups)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
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)
class ObjectPermissionTestCase(TestCase): class ObjectPermissionTestCase(TestCase, BaseFilterSetTests):
queryset = ObjectPermission.objects.all() queryset = ObjectPermission.objects.all()
filterset = ObjectPermissionFilterSet filterset = ObjectPermissionFilterSet
@ -160,10 +153,6 @@ class ObjectPermissionTestCase(TestCase):
permissions[i].users.set([users[i]]) permissions[i].users.set([users[i]])
permissions[i].object_types.set([object_types[i]]) permissions[i].object_types.set([object_types[i]])
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Permission 1', 'Permission 2']} params = {'name': ['Permission 1', 'Permission 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -1,17 +1,9 @@
import django_filters import django_filters
from django_filters.constants import EMPTY_VALUES
from copy import deepcopy
from dcim.forms import MACAddressField
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.db import models from django_filters.constants import EMPTY_VALUES
from django_filters.utils import get_model_field, resolve_field
from extras.models import Tag from dcim.forms import MACAddressField
from utilities.constants import (
FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP,
FILTER_NUMERIC_BASED_LOOKUP_MAP
)
def multivalue_field_factory(field_class): def multivalue_field_factory(field_class):
@ -91,21 +83,6 @@ class NullableCharFieldFilter(django_filters.CharFilter):
return qs.distinct() if self.distinct else qs return qs.distinct() if self.distinct else qs
class TagFilter(django_filters.ModelMultipleChoiceFilter):
"""
Match on one or more assigned tags. If multiple tags are specified (e.g. ?tag=foo&tag=bar), the queryset is filtered
to objects matching all tags.
"""
def __init__(self, *args, **kwargs):
kwargs.setdefault('field_name', 'tags__slug')
kwargs.setdefault('to_field_name', 'slug')
kwargs.setdefault('conjoined', True)
kwargs.setdefault('queryset', Tag.objects.all())
super().__init__(*args, **kwargs)
class NumericArrayFilter(django_filters.NumberFilter): class NumericArrayFilter(django_filters.NumberFilter):
""" """
Filter based on the presence of an integer within an ArrayField. Filter based on the presence of an integer within an ArrayField.
@ -134,182 +111,3 @@ class ContentTypeFilter(django_filters.CharFilter):
f'{self.field_name}__model': model f'{self.field_name}__model': model
} }
) )
#
# FilterSets
#
class BaseFilterSet(django_filters.FilterSet):
"""
A base filterset which provides common functionaly to all NetBox filtersets
"""
FILTER_DEFAULTS = deepcopy(django_filters.filterset.FILTER_FOR_DBFIELD_DEFAULTS)
FILTER_DEFAULTS.update({
models.AutoField: {
'filter_class': MultiValueNumberFilter
},
models.CharField: {
'filter_class': MultiValueCharFilter
},
models.DateField: {
'filter_class': MultiValueDateFilter
},
models.DateTimeField: {
'filter_class': MultiValueDateTimeFilter
},
models.DecimalField: {
'filter_class': MultiValueNumberFilter
},
models.EmailField: {
'filter_class': MultiValueCharFilter
},
models.FloatField: {
'filter_class': MultiValueNumberFilter
},
models.IntegerField: {
'filter_class': MultiValueNumberFilter
},
models.PositiveIntegerField: {
'filter_class': MultiValueNumberFilter
},
models.PositiveSmallIntegerField: {
'filter_class': MultiValueNumberFilter
},
models.SlugField: {
'filter_class': MultiValueCharFilter
},
models.SmallIntegerField: {
'filter_class': MultiValueNumberFilter
},
models.TimeField: {
'filter_class': MultiValueTimeFilter
},
models.URLField: {
'filter_class': MultiValueCharFilter
},
MACAddressField: {
'filter_class': MultiValueMACAddressFilter
},
})
@staticmethod
def _get_filter_lookup_dict(existing_filter):
# Choose the lookup expression map based on the filter type
if isinstance(existing_filter, (
MultiValueDateFilter,
MultiValueDateTimeFilter,
MultiValueNumberFilter,
MultiValueTimeFilter
)):
lookup_map = FILTER_NUMERIC_BASED_LOOKUP_MAP
elif isinstance(existing_filter, (
TreeNodeMultipleChoiceFilter,
)):
# TreeNodeMultipleChoiceFilter only support negation but must maintain the `in` lookup expression
lookup_map = FILTER_TREENODE_NEGATION_LOOKUP_MAP
elif isinstance(existing_filter, (
django_filters.ModelChoiceFilter,
django_filters.ModelMultipleChoiceFilter,
TagFilter
)) or existing_filter.extra.get('choices'):
# These filter types support only negation
lookup_map = FILTER_NEGATION_LOOKUP_MAP
elif isinstance(existing_filter, (
django_filters.filters.CharFilter,
django_filters.MultipleChoiceFilter,
MultiValueCharFilter,
MultiValueMACAddressFilter
)):
lookup_map = FILTER_CHAR_BASED_LOOKUP_MAP
else:
lookup_map = None
return lookup_map
@classmethod
def get_filters(cls):
"""
Override filter generation to support dynamic lookup expressions for certain filter types.
For specific filter types, new filters are created based on defined lookup expressions in
the form `<field_name>__<lookup_expr>`
"""
filters = super().get_filters()
new_filters = {}
for existing_filter_name, existing_filter in filters.items():
# Loop over existing filters to extract metadata by which to create new filters
# If the filter makes use of a custom filter method or lookup expression skip it
# as we cannot sanely handle these cases in a generic mannor
if existing_filter.method is not None or existing_filter.lookup_expr not in ['exact', 'in']:
continue
# Choose the lookup expression map based on the filter type
lookup_map = cls._get_filter_lookup_dict(existing_filter)
if lookup_map is None:
# Do not augment this filter type with more lookup expressions
continue
# Get properties of the existing filter for later use
field_name = existing_filter.field_name
field = get_model_field(cls._meta.model, field_name)
# Create new filters for each lookup expression in the map
for lookup_name, lookup_expr in lookup_map.items():
new_filter_name = '{}__{}'.format(existing_filter_name, lookup_name)
try:
if existing_filter_name in cls.declared_filters:
# The filter field has been explicity defined on the filterset class so we must manually
# create the new filter with the same type because there is no guarantee the defined type
# is the same as the default type for the field
resolve_field(field, lookup_expr) # Will raise FieldLookupError if the lookup is invalid
new_filter = type(existing_filter)(
field_name=field_name,
lookup_expr=lookup_expr,
label=existing_filter.label,
exclude=existing_filter.exclude,
distinct=existing_filter.distinct,
**existing_filter.extra
)
else:
# The filter field is listed in Meta.fields so we can safely rely on default behaviour
# Will raise FieldLookupError if the lookup is invalid
new_filter = cls.filter_for_field(field, field_name, lookup_expr)
except django_filters.exceptions.FieldLookupError:
# The filter could not be created because the lookup expression is not supported on the field
continue
if lookup_name.startswith('n'):
# This is a negation filter which requires a queryset.exclude() clause
# Of course setting the negation of the existing filter's exclude attribute handles both cases
new_filter.exclude = not existing_filter.exclude
new_filters[new_filter_name] = new_filter
filters.update(new_filters)
return filters
class NameSlugSearchFilterSet(django_filters.FilterSet):
"""
A base class for adding the search method to models which only expose the `name` and `slug` fields
"""
q = django_filters.CharFilter(
method='search',
label='Search',
)
def search(self, queryset, name, value):
if not value.strip():
return queryset
return queryset.filter(
models.Q(name__icontains=value) |
models.Q(slug__icontains=value)
)

View File

@ -1,4 +1,5 @@
from .api import * from .api import *
from .base import * from .base import *
from .filtersets import *
from .utils import * from .utils import *
from .views import * from .views import *

View File

@ -0,0 +1,35 @@
from datetime import date, datetime, timezone
__all__ = (
'BaseFilterSetTests',
'ChangeLoggedFilterSetTests',
)
class BaseFilterSetTests:
queryset = None
filterset = None
def test_id(self):
"""
Test filtering for two PKs from a set of >2 objects.
"""
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertGreater(self.queryset.count(), 2)
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ChangeLoggedFilterSetTests(BaseFilterSetTests):
def test_created(self):
pk_list = self.queryset.values_list('pk', flat=True)[:2]
self.queryset.filter(pk__in=pk_list).update(created=date(2021, 1, 1))
params = {'created': '2021-01-01'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_last_updated(self):
pk_list = self.queryset.values_list('pk', flat=True)[:2]
self.queryset.filter(pk__in=pk_list).update(last_updated=datetime(2021, 1, 1, 0, 0, 0, tzinfo=timezone.utc))
params = {'last_updated': '2021-01-01T00:00:00'}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -7,14 +7,16 @@ from taggit.managers import TaggableManager
from dcim.choices import * from dcim.choices import *
from dcim.fields import MACAddressField from dcim.fields import MACAddressField
from dcim.filters import DeviceFilterSet, SiteFilterSet from dcim.filtersets import DeviceFilterSet, SiteFilterSet
from dcim.models import ( from dcim.models import (
Device, DeviceRole, DeviceType, Interface, Manufacturer, Platform, Rack, Region, Site Device, DeviceRole, DeviceType, Interface, Manufacturer, Platform, Rack, Region, Site
) )
from extras.filters import TagFilter
from extras.models import TaggedItem from extras.models import TaggedItem
from netbox.filtersets import BaseFilterSet
from utilities.filters import ( from utilities.filters import (
BaseFilterSet, MACAddressFilter, MultiValueCharFilter, MultiValueDateFilter, MultiValueDateTimeFilter, MACAddressFilter, MultiValueCharFilter, MultiValueDateFilter, MultiValueDateTimeFilter, MultiValueNumberFilter,
MultiValueNumberFilter, MultiValueTimeFilter, TagFilter, TreeNodeMultipleChoiceFilter, MultiValueTimeFilter, TreeNodeMultipleChoiceFilter,
) )

View File

@ -3,7 +3,7 @@ from rest_framework.routers import APIRootView
from dcim.models import Device from dcim.models import Device
from extras.api.views import ConfigContextQuerySetMixin, CustomFieldModelViewSet, ModelViewSet from extras.api.views import ConfigContextQuerySetMixin, CustomFieldModelViewSet, ModelViewSet
from utilities.utils import count_related from utilities.utils import count_related
from virtualization import filters from virtualization import filtersets
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
from . import serializers from . import serializers
@ -25,7 +25,7 @@ class ClusterTypeViewSet(CustomFieldModelViewSet):
cluster_count=count_related(Cluster, 'type') cluster_count=count_related(Cluster, 'type')
) )
serializer_class = serializers.ClusterTypeSerializer serializer_class = serializers.ClusterTypeSerializer
filterset_class = filters.ClusterTypeFilterSet filterset_class = filtersets.ClusterTypeFilterSet
class ClusterGroupViewSet(CustomFieldModelViewSet): class ClusterGroupViewSet(CustomFieldModelViewSet):
@ -33,7 +33,7 @@ class ClusterGroupViewSet(CustomFieldModelViewSet):
cluster_count=count_related(Cluster, 'group') cluster_count=count_related(Cluster, 'group')
) )
serializer_class = serializers.ClusterGroupSerializer serializer_class = serializers.ClusterGroupSerializer
filterset_class = filters.ClusterGroupFilterSet filterset_class = filtersets.ClusterGroupFilterSet
class ClusterViewSet(CustomFieldModelViewSet): class ClusterViewSet(CustomFieldModelViewSet):
@ -44,7 +44,7 @@ class ClusterViewSet(CustomFieldModelViewSet):
virtualmachine_count=count_related(VirtualMachine, 'cluster') virtualmachine_count=count_related(VirtualMachine, 'cluster')
) )
serializer_class = serializers.ClusterSerializer serializer_class = serializers.ClusterSerializer
filterset_class = filters.ClusterFilterSet filterset_class = filtersets.ClusterFilterSet
# #
@ -55,7 +55,7 @@ class VirtualMachineViewSet(ConfigContextQuerySetMixin, CustomFieldModelViewSet)
queryset = VirtualMachine.objects.prefetch_related( queryset = VirtualMachine.objects.prefetch_related(
'cluster__site', 'role', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'tags' 'cluster__site', 'role', 'tenant', 'platform', 'primary_ip4', 'primary_ip6', 'tags'
) )
filterset_class = filters.VirtualMachineFilterSet filterset_class = filtersets.VirtualMachineFilterSet
def get_serializer_class(self): def get_serializer_class(self):
""" """
@ -83,5 +83,5 @@ class VMInterfaceViewSet(ModelViewSet):
'virtual_machine', 'parent', 'tags', 'tagged_vlans', 'ip_addresses' 'virtual_machine', 'parent', 'tags', 'tagged_vlans', 'ip_addresses'
) )
serializer_class = serializers.VMInterfaceSerializer serializer_class = serializers.VMInterfaceSerializer
filterset_class = filters.VMInterfaceFilterSet filterset_class = filtersets.VMInterfaceFilterSet
brief_prefetch_fields = ['virtual_machine'] brief_prefetch_fields = ['virtual_machine']

View File

@ -2,12 +2,11 @@ import django_filters
from django.db.models import Q from django.db.models import Q
from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup
from extras.filters import CustomFieldModelFilterSet, CreatedUpdatedFilterSet, LocalConfigContextFilterSet from extras.filters import TagFilter
from tenancy.filters import TenancyFilterSet from extras.filtersets import LocalConfigContextFilterSet
from utilities.filters import ( from netbox.filtersets import OrganizationalModelFilterSet, PrimaryModelFilterSet
BaseFilterSet, MultiValueMACAddressFilter, NameSlugSearchFilterSet, TagFilter, from tenancy.filtersets import TenancyFilterSet
TreeNodeMultipleChoiceFilter, from utilities.filters import MultiValueMACAddressFilter, TreeNodeMultipleChoiceFilter
)
from .choices import * from .choices import *
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
@ -20,21 +19,21 @@ __all__ = (
) )
class ClusterTypeFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class ClusterTypeFilterSet(OrganizationalModelFilterSet):
class Meta: class Meta:
model = ClusterType model = ClusterType
fields = ['id', 'name', 'slug', 'description'] fields = ['id', 'name', 'slug', 'description']
class ClusterGroupFilterSet(BaseFilterSet, NameSlugSearchFilterSet, CreatedUpdatedFilterSet): class ClusterGroupFilterSet(OrganizationalModelFilterSet):
class Meta: class Meta:
model = ClusterGroup model = ClusterGroup
fields = ['id', 'name', 'slug', 'description'] fields = ['id', 'name', 'slug', 'description']
class ClusterFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class ClusterFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -110,13 +109,7 @@ class ClusterFilterSet(BaseFilterSet, TenancyFilterSet, CustomFieldModelFilterSe
) )
class VirtualMachineFilterSet( class VirtualMachineFilterSet(PrimaryModelFilterSet, TenancyFilterSet, LocalConfigContextFilterSet):
BaseFilterSet,
LocalConfigContextFilterSet,
TenancyFilterSet,
CustomFieldModelFilterSet,
CreatedUpdatedFilterSet
):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',
@ -237,7 +230,7 @@ class VirtualMachineFilterSet(
return queryset.exclude(params) return queryset.exclude(params)
class VMInterfaceFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet): class VMInterfaceFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',

View File

@ -646,7 +646,7 @@ class VMInterfaceForm(BootstrapMixin, InterfaceCommonForm, CustomFieldModelForm)
vm_id = self.initial.get('virtual_machine') or self.data.get('virtual_machine') vm_id = self.initial.get('virtual_machine') or self.data.get('virtual_machine')
# Restrict parent interface assignment by VM # Restrict parent interface assignment by VM
self.fields['parent'].widget.add_query_param('virtualmachine_id', vm_id) self.fields['parent'].widget.add_query_param('virtual_machine_id', vm_id)
# Limit VLAN choices by virtual machine # Limit VLAN choices by virtual machine
self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id) self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id)
@ -668,7 +668,7 @@ class VMInterfaceCreateForm(BootstrapMixin, InterfaceCommonForm):
queryset=VMInterface.objects.all(), queryset=VMInterface.objects.all(),
required=False, required=False,
query_params={ query_params={
'virtualmachine_id': 'virtual_machine', 'virtual_machine_id': '$virtual_machine',
} }
) )
mtu = forms.IntegerField( mtu = forms.IntegerField(
@ -711,9 +711,6 @@ class VMInterfaceCreateForm(BootstrapMixin, InterfaceCommonForm):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
vm_id = self.initial.get('virtual_machine') or self.data.get('virtual_machine') vm_id = self.initial.get('virtual_machine') or self.data.get('virtual_machine')
# Restrict parent interface assignment by VM
self.fields['parent'].widget.add_query_param('virtualmachine_id', vm_id)
# Limit VLAN choices by virtual machine # Limit VLAN choices by virtual machine
self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id) self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id)
self.fields['tagged_vlans'].widget.add_query_param('available_on_virtualmachine', vm_id) self.fields['tagged_vlans'].widget.add_query_param('available_on_virtualmachine', vm_id)
@ -796,7 +793,7 @@ class VMInterfaceBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
vm_id = self.initial.get('virtual_machine') vm_id = self.initial.get('virtual_machine')
# Restrict parent interface assignment by VM # Restrict parent interface assignment by VM
self.fields['parent'].widget.add_query_param('virtualmachine_id', vm_id) self.fields['parent'].widget.add_query_param('virtual_machine_id', vm_id)
# Limit VLAN choices by virtual machine # Limit VLAN choices by virtual machine
self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id) self.fields['untagged_vlan'].widget.add_query_param('available_on_virtualmachine', vm_id)

View File

@ -3,12 +3,13 @@ from django.test import TestCase
from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, Platform, Region, Site, SiteGroup
from ipam.models import IPAddress from ipam.models import IPAddress
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from utilities.testing import ChangeLoggedFilterSetTests
from virtualization.choices import * from virtualization.choices import *
from virtualization.filters import * from virtualization.filtersets import *
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
class ClusterTypeTestCase(TestCase): class ClusterTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = ClusterType.objects.all() queryset = ClusterType.objects.all()
filterset = ClusterTypeFilterSet filterset = ClusterTypeFilterSet
@ -22,10 +23,6 @@ class ClusterTypeTestCase(TestCase):
) )
ClusterType.objects.bulk_create(cluster_types) ClusterType.objects.bulk_create(cluster_types)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Cluster Type 1', 'Cluster Type 2']} params = {'name': ['Cluster Type 1', 'Cluster Type 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -39,7 +36,7 @@ class ClusterTypeTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ClusterGroupTestCase(TestCase): class ClusterGroupTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = ClusterGroup.objects.all() queryset = ClusterGroup.objects.all()
filterset = ClusterGroupFilterSet filterset = ClusterGroupFilterSet
@ -53,10 +50,6 @@ class ClusterGroupTestCase(TestCase):
) )
ClusterGroup.objects.bulk_create(cluster_groups) ClusterGroup.objects.bulk_create(cluster_groups)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Cluster Group 1', 'Cluster Group 2']} params = {'name': ['Cluster Group 1', 'Cluster Group 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -70,7 +63,7 @@ class ClusterGroupTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class ClusterTestCase(TestCase): class ClusterTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = Cluster.objects.all() queryset = Cluster.objects.all()
filterset = ClusterFilterSet filterset = ClusterFilterSet
@ -136,10 +129,6 @@ class ClusterTestCase(TestCase):
) )
Cluster.objects.bulk_create(clusters) Cluster.objects.bulk_create(clusters)
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Cluster 1', 'Cluster 2']} params = {'name': ['Cluster 1', 'Cluster 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -194,7 +183,7 @@ class ClusterTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class VirtualMachineTestCase(TestCase): class VirtualMachineTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VirtualMachine.objects.all() queryset = VirtualMachine.objects.all()
filterset = VirtualMachineFilterSet filterset = VirtualMachineFilterSet
@ -297,10 +286,6 @@ class VirtualMachineTestCase(TestCase):
VirtualMachine.objects.filter(pk=vms[0].pk).update(primary_ip4=ipaddresses[0]) VirtualMachine.objects.filter(pk=vms[0].pk).update(primary_ip4=ipaddresses[0])
VirtualMachine.objects.filter(pk=vms[1].pk).update(primary_ip4=ipaddresses[1]) VirtualMachine.objects.filter(pk=vms[1].pk).update(primary_ip4=ipaddresses[1])
def test_id(self):
params = {'id': self.queryset.values_list('pk', flat=True)[:2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Virtual Machine 1', 'Virtual Machine 2']} params = {'name': ['Virtual Machine 1', 'Virtual Machine 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -409,7 +394,7 @@ class VirtualMachineTestCase(TestCase):
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class VMInterfaceTestCase(TestCase): class VMInterfaceTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = VMInterface.objects.all() queryset = VMInterface.objects.all()
filterset = VMInterfaceFilterSet filterset = VMInterfaceFilterSet
@ -444,11 +429,6 @@ class VMInterfaceTestCase(TestCase):
) )
VMInterface.objects.bulk_create(interfaces) VMInterface.objects.bulk_create(interfaces)
def test_id(self):
id_list = self.queryset.values_list('id', flat=True)[:2]
params = {'id': [str(id) for id in id_list]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_name(self): def test_name(self):
params = {'name': ['Interface 1', 'Interface 2']} params = {'name': ['Interface 1', 'Interface 2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -13,7 +13,7 @@ from netbox.views import generic
from secrets.models import Secret from secrets.models import Secret
from utilities.tables import paginate_table from utilities.tables import paginate_table
from utilities.utils import count_related from utilities.utils import count_related
from . import filters, forms, tables from . import filtersets, forms, tables
from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface from .models import Cluster, ClusterGroup, ClusterType, VirtualMachine, VMInterface
@ -64,7 +64,7 @@ class ClusterTypeBulkEditView(generic.BulkEditView):
queryset = ClusterType.objects.annotate( queryset = ClusterType.objects.annotate(
cluster_count=count_related(Cluster, 'type') cluster_count=count_related(Cluster, 'type')
) )
filterset = filters.ClusterTypeFilterSet filterset = filtersets.ClusterTypeFilterSet
table = tables.ClusterTypeTable table = tables.ClusterTypeTable
form = forms.ClusterTypeBulkEditForm form = forms.ClusterTypeBulkEditForm
@ -125,7 +125,7 @@ class ClusterGroupBulkEditView(generic.BulkEditView):
queryset = ClusterGroup.objects.annotate( queryset = ClusterGroup.objects.annotate(
cluster_count=count_related(Cluster, 'group') cluster_count=count_related(Cluster, 'group')
) )
filterset = filters.ClusterGroupFilterSet filterset = filtersets.ClusterGroupFilterSet
table = tables.ClusterGroupTable table = tables.ClusterGroupTable
form = forms.ClusterGroupBulkEditForm form = forms.ClusterGroupBulkEditForm
@ -148,7 +148,7 @@ class ClusterListView(generic.ObjectListView):
vm_count=count_related(VirtualMachine, 'cluster') vm_count=count_related(VirtualMachine, 'cluster')
) )
table = tables.ClusterTable table = tables.ClusterTable
filterset = filters.ClusterFilterSet filterset = filtersets.ClusterFilterSet
filterset_form = forms.ClusterFilterForm filterset_form = forms.ClusterFilterForm
@ -205,14 +205,14 @@ class ClusterBulkImportView(generic.BulkImportView):
class ClusterBulkEditView(generic.BulkEditView): class ClusterBulkEditView(generic.BulkEditView):
queryset = Cluster.objects.prefetch_related('type', 'group', 'site') queryset = Cluster.objects.prefetch_related('type', 'group', 'site')
filterset = filters.ClusterFilterSet filterset = filtersets.ClusterFilterSet
table = tables.ClusterTable table = tables.ClusterTable
form = forms.ClusterBulkEditForm form = forms.ClusterBulkEditForm
class ClusterBulkDeleteView(generic.BulkDeleteView): class ClusterBulkDeleteView(generic.BulkDeleteView):
queryset = Cluster.objects.prefetch_related('type', 'group', 'site') queryset = Cluster.objects.prefetch_related('type', 'group', 'site')
filterset = filters.ClusterFilterSet filterset = filtersets.ClusterFilterSet
table = tables.ClusterTable table = tables.ClusterTable
@ -304,7 +304,7 @@ class ClusterRemoveDevicesView(generic.ObjectEditView):
class VirtualMachineListView(generic.ObjectListView): class VirtualMachineListView(generic.ObjectListView):
queryset = VirtualMachine.objects.all() queryset = VirtualMachine.objects.all()
filterset = filters.VirtualMachineFilterSet filterset = filtersets.VirtualMachineFilterSet
filterset_form = forms.VirtualMachineFilterForm filterset_form = forms.VirtualMachineFilterForm
table = tables.VirtualMachineDetailTable table = tables.VirtualMachineDetailTable
template_name = 'virtualization/virtualmachine_list.html' template_name = 'virtualization/virtualmachine_list.html'
@ -388,14 +388,14 @@ class VirtualMachineBulkImportView(generic.BulkImportView):
class VirtualMachineBulkEditView(generic.BulkEditView): class VirtualMachineBulkEditView(generic.BulkEditView):
queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role') queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role')
filterset = filters.VirtualMachineFilterSet filterset = filtersets.VirtualMachineFilterSet
table = tables.VirtualMachineTable table = tables.VirtualMachineTable
form = forms.VirtualMachineBulkEditForm form = forms.VirtualMachineBulkEditForm
class VirtualMachineBulkDeleteView(generic.BulkDeleteView): class VirtualMachineBulkDeleteView(generic.BulkDeleteView):
queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role') queryset = VirtualMachine.objects.prefetch_related('cluster', 'tenant', 'role')
filterset = filters.VirtualMachineFilterSet filterset = filtersets.VirtualMachineFilterSet
table = tables.VirtualMachineTable table = tables.VirtualMachineTable
@ -405,7 +405,7 @@ class VirtualMachineBulkDeleteView(generic.BulkDeleteView):
class VMInterfaceListView(generic.ObjectListView): class VMInterfaceListView(generic.ObjectListView):
queryset = VMInterface.objects.all() queryset = VMInterface.objects.all()
filterset = filters.VMInterfaceFilterSet filterset = filtersets.VMInterfaceFilterSet
filterset_form = forms.VMInterfaceFilterForm filterset_form = forms.VMInterfaceFilterForm
table = tables.VMInterfaceTable table = tables.VMInterfaceTable
action_buttons = ('export',) action_buttons = ('export',)
@ -500,7 +500,7 @@ class VirtualMachineBulkAddInterfaceView(generic.BulkComponentCreateView):
form = forms.VMInterfaceBulkCreateForm form = forms.VMInterfaceBulkCreateForm
queryset = VMInterface.objects.all() queryset = VMInterface.objects.all()
model_form = forms.VMInterfaceForm model_form = forms.VMInterfaceForm
filterset = filters.VirtualMachineFilterSet filterset = filtersets.VirtualMachineFilterSet
table = tables.VirtualMachineTable table = tables.VirtualMachineTable
def get_required_permission(self): def get_required_permission(self):