Closes #20304: Object owners (#20634)
Some checks failed
CI / build (20.x, 3.12) (push) Has been cancelled
CI / build (20.x, 3.13) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, actions) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (${{ matrix.language }}) (none, python) (push) Has been cancelled

This commit is contained in:
Jeremy Stretch
2025-10-24 16:08:01 -04:00
committed by GitHub
parent 52d4498caf
commit be74436884
196 changed files with 15831 additions and 2715 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
# Resource Ownership
!!! info "This feature was introduced in NetBox v4.5."
Most objects in NetBox can be assigned an owner. An owner is a set of users and/or groups who are responsible for the administration of associated objects. For example, you might designate the operations team at a site as the owner for all prefixes and VLANs deployed at that site. The users and groups assigned to an owner are referred to as its members.
!!! note
Ownership of an object should not be confused with the concept of [tenancy](./tenancy.md), which indicates the dedication of an object to a specific tenant. For instance, a tenant might represent a customer served by the object, whereas an owner typically represents a set of internal users responsible for the management of the object.
Owners can be organized into groups for easier management.

View File

@@ -1,6 +1,6 @@
# Tenancy # Tenancy
Most core objects within NetBox's data model support _tenancy_. This is the association of an object with a particular tenant to convey ownership or dependency. For example, an enterprise might represent its internal business units as tenants, whereas a managed services provider might create a tenant in NetBox to represent each of its customers. Most core objects within NetBox's data model support _tenancy_. This is the association of an object with a particular tenant to convey assignment or dependency. For example, an enterprise might represent its internal business units as tenants, whereas a managed services provider might create a tenant in NetBox to represent each of its customers.
```mermaid ```mermaid
flowchart TD flowchart TD
@@ -19,20 +19,36 @@ Tenants can be grouped by any logic that your use case demands, and groups can b
Typically, the tenant model is used to represent a customer or internal organization, however it can be used for whatever purpose meets your needs. Typically, the tenant model is used to represent a customer or internal organization, however it can be used for whatever purpose meets your needs.
Most core objects within NetBox can be assigned to particular tenant, so this model provides a very convenient way to correlate ownership across object types. For example, each of your customers might have its own racks, devices, IP addresses, circuits and so on: These can all be easily tracked via tenant assignment. Most core objects within NetBox can be assigned to a particular tenant, so this model provides a very convenient way to correlate resource allocation across object types. For example, each of your customers might have its own racks, devices, IP addresses, circuits and so on: These can all be easily tracked via tenant assignment.
The following objects can be assigned to tenants: The following objects can be assigned to tenants:
* Sites * Circuits
* Circuit groups
* Virtual circuits
* Cables
* Devices
* Virtual device contexts
* Power feeds
* Racks * Racks
* Rack reservations * Rack reservations
* Devices * Sites
* VRFs * Locations
* ASNs
* ASN ranges
* Aggregates
* Prefixes * Prefixes
* IP ranges
* IP addresses * IP addresses
* VLANs * VLANs
* Circuits * VLAN groups
* VRFs
* Route targets
* Clusters * Clusters
* Virtual machines * Virtual machines
* L2VPNs
* Tunnels
* Wireless LANs
* Wireless links
Tenant assignment is used to signify the ownership of an object in NetBox. As such, each object may only be owned by a single tenant. For example, if you have a firewall dedicated to a particular customer, you would assign it to the tenant which represents that customer. However, if the firewall serves multiple customers, it doesn't *belong* to any particular customer, so tenant assignment would not be appropriate. Tenancy represents the dedication of an object to a specific tenant. As such, each object may only be assigned to a single tenant. For example, if you have a firewall dedicated to a particular customer, you would assign it to the tenant which represents that customer. However, if the firewall serves multiple customers, it doesn't *belong* to any particular customer, so the assignment of a tenant would not be appropriate.

View File

@@ -0,0 +1,23 @@
# Owner
An owner is a set of users and/or groups who are responsible for the administration of certain resources within NetBox. The users and groups assigned to an owner are referred to as its members. Owner assignments are useful for indicating which parties are responsible for the administration of a particular object.
Most objects within NetBox can be assigned an owner, although this is not required.
## Fields
### Name
The owner's name.
### Group
The [group](./ownergroup.md) to which the owner is assigned. The assignment of an owner to a group is optional.
### User Groups
Groups of users that are members of the owner.
### Users
Individual users that are members of the owner.

View File

@@ -0,0 +1,9 @@
# Owner Groups
Groups are used to correlate and organize [owners](./owner.md). The assignment of an owner to a group has no bearing on the relationship of owned objects to their owners.
## Fields
### Name
The name of the group.

View File

@@ -77,6 +77,7 @@ nav:
- Wireless: 'features/wireless.md' - Wireless: 'features/wireless.md'
- Virtualization: 'features/virtualization.md' - Virtualization: 'features/virtualization.md'
- VPN Tunnels: 'features/vpn-tunnels.md' - VPN Tunnels: 'features/vpn-tunnels.md'
- Resource Ownership: 'features/resource-ownership.md'
- Tenancy: 'features/tenancy.md' - Tenancy: 'features/tenancy.md'
- Contacts: 'features/contacts.md' - Contacts: 'features/contacts.md'
- Search: 'features/search.md' - Search: 'features/search.md'
@@ -273,6 +274,9 @@ nav:
- ContactRole: 'models/tenancy/contactrole.md' - ContactRole: 'models/tenancy/contactrole.md'
- Tenant: 'models/tenancy/tenant.md' - Tenant: 'models/tenancy/tenant.md'
- TenantGroup: 'models/tenancy/tenantgroup.md' - TenantGroup: 'models/tenancy/tenantgroup.md'
- Users:
- Owner: 'models/users/owner.md'
- OwnerGroup: 'models/users/ownergroup.md'
- Virtualization: - Virtualization:
- Cluster: 'models/virtualization/cluster.md' - Cluster: 'models/virtualization/cluster.md'
- ClusterGroup: 'models/virtualization/clustergroup.md' - ClusterGroup: 'models/virtualization/clustergroup.md'

View File

@@ -11,7 +11,9 @@ from circuits.models import (
from dcim.api.serializers_.device_components import InterfaceSerializer from dcim.api.serializers_.device_components import InterfaceSerializer
from dcim.api.serializers_.cables import CabledObjectSerializer from dcim.api.serializers_.cables import CabledObjectSerializer
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer, WritableNestedSerializer from netbox.api.serializers import (
NetBoxModelSerializer, OrganizationalModelSerializer, PrimaryModelSerializer, WritableNestedSerializer,
)
from netbox.choices import DistanceUnitChoices from netbox.choices import DistanceUnitChoices
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
@@ -29,7 +31,7 @@ __all__ = (
) )
class CircuitTypeSerializer(NetBoxModelSerializer): class CircuitTypeSerializer(OrganizationalModelSerializer):
# Related object counts # Related object counts
circuit_count = RelatedObjectCountField('circuits') circuit_count = RelatedObjectCountField('circuits')
@@ -37,8 +39,8 @@ class CircuitTypeSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = CircuitType model = CircuitType
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'owner', 'tags',
'created', 'last_updated', 'circuit_count', 'custom_fields', 'created', 'last_updated', 'circuit_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'circuit_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'circuit_count')
@@ -71,15 +73,15 @@ class CircuitCircuitTerminationSerializer(WritableNestedSerializer):
return serializer(obj.termination, nested=True, context=context).data return serializer(obj.termination, nested=True, context=context).data
class CircuitGroupSerializer(NetBoxModelSerializer): class CircuitGroupSerializer(OrganizationalModelSerializer):
tenant = TenantSerializer(nested=True, required=False, allow_null=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True)
circuit_count = RelatedObjectCountField('assignments') circuit_count = RelatedObjectCountField('assignments')
class Meta: class Meta:
model = CircuitGroup model = CircuitGroup
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'tenant', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'tenant', 'owner', 'tags',
'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count' 'custom_fields', 'created', 'last_updated', 'circuit_count'
] ]
brief_fields = ('id', 'url', 'display', 'name') brief_fields = ('id', 'url', 'display', 'name')
@@ -99,7 +101,7 @@ class CircuitGroupAssignmentSerializer_(NetBoxModelSerializer):
brief_fields = ('id', 'url', 'display', 'group', 'priority') brief_fields = ('id', 'url', 'display', 'group', 'priority')
class CircuitSerializer(NetBoxModelSerializer): class CircuitSerializer(PrimaryModelSerializer):
provider = ProviderSerializer(nested=True) provider = ProviderSerializer(nested=True)
provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None) provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None)
status = ChoiceField(choices=CircuitStatusChoices, required=False) status = ChoiceField(choices=CircuitStatusChoices, required=False)
@@ -115,7 +117,7 @@ class CircuitSerializer(NetBoxModelSerializer):
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'cid', 'provider', 'provider_account', 'type', 'status', 'tenant', 'id', 'url', 'display_url', 'display', 'cid', 'provider', 'provider_account', 'type', 'status', 'tenant',
'install_date', 'termination_date', 'commit_rate', 'description', 'distance', 'distance_unit', 'install_date', 'termination_date', 'commit_rate', 'description', 'distance', 'distance_unit',
'termination_a', 'termination_z', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'termination_a', 'termination_z', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
'assignments', 'assignments',
] ]
brief_fields = ('id', 'url', 'display', 'provider', 'cid', 'description') brief_fields = ('id', 'url', 'display', 'provider', 'cid', 'description')
@@ -176,7 +178,7 @@ class CircuitGroupAssignmentSerializer(CircuitGroupAssignmentSerializer_):
return serializer(obj.member, nested=True, context=context).data return serializer(obj.member, nested=True, context=context).data
class VirtualCircuitTypeSerializer(NetBoxModelSerializer): class VirtualCircuitTypeSerializer(OrganizationalModelSerializer):
# Related object counts # Related object counts
virtual_circuit_count = RelatedObjectCountField('virtual_circuits') virtual_circuit_count = RelatedObjectCountField('virtual_circuits')
@@ -184,13 +186,13 @@ class VirtualCircuitTypeSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = VirtualCircuitType model = VirtualCircuitType
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'owner', 'tags',
'created', 'last_updated', 'virtual_circuit_count', 'custom_fields', 'created', 'last_updated', 'virtual_circuit_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'virtual_circuit_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'virtual_circuit_count')
class VirtualCircuitSerializer(NetBoxModelSerializer): class VirtualCircuitSerializer(PrimaryModelSerializer):
provider_network = ProviderNetworkSerializer(nested=True) provider_network = ProviderNetworkSerializer(nested=True)
provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None) provider_account = ProviderAccountSerializer(nested=True, required=False, allow_null=True, default=None)
type = VirtualCircuitTypeSerializer(nested=True) type = VirtualCircuitTypeSerializer(nested=True)
@@ -201,7 +203,7 @@ class VirtualCircuitSerializer(NetBoxModelSerializer):
model = VirtualCircuit model = VirtualCircuit
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'cid', 'provider_network', 'provider_account', 'type', 'status', 'id', 'url', 'display_url', 'display', 'cid', 'provider_network', 'provider_account', 'type', 'status',
'tenant', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'tenant', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'provider_network', 'cid', 'description') brief_fields = ('id', 'url', 'display', 'provider_network', 'cid', 'description')

View File

@@ -4,7 +4,7 @@ from circuits.models import Provider, ProviderAccount, ProviderNetwork
from ipam.api.serializers_.asns import ASNSerializer from ipam.api.serializers_.asns import ASNSerializer
from ipam.models import ASN from ipam.models import ASN
from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import PrimaryModelSerializer
from .nested import NestedProviderAccountSerializer from .nested import NestedProviderAccountSerializer
__all__ = ( __all__ = (
@@ -14,7 +14,7 @@ __all__ = (
) )
class ProviderSerializer(NetBoxModelSerializer): class ProviderSerializer(PrimaryModelSerializer):
accounts = SerializedPKRelatedField( accounts = SerializedPKRelatedField(
queryset=ProviderAccount.objects.all(), queryset=ProviderAccount.objects.all(),
serializer=NestedProviderAccountSerializer, serializer=NestedProviderAccountSerializer,
@@ -35,32 +35,32 @@ class ProviderSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = Provider model = Provider
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'accounts', 'description', 'comments', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'accounts', 'description', 'owner', 'comments',
'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count', 'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'circuit_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'circuit_count')
class ProviderAccountSerializer(NetBoxModelSerializer): class ProviderAccountSerializer(PrimaryModelSerializer):
provider = ProviderSerializer(nested=True) provider = ProviderSerializer(nested=True)
name = serializers.CharField(allow_blank=True, max_length=100, required=False, default='') name = serializers.CharField(allow_blank=True, max_length=100, required=False, default='')
class Meta: class Meta:
model = ProviderAccount model = ProviderAccount
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'provider', 'name', 'account', 'description', 'comments', 'tags', 'id', 'url', 'display_url', 'display', 'provider', 'name', 'account', 'description', 'owner', 'comments',
'custom_fields', 'created', 'last_updated', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'account', 'description') brief_fields = ('id', 'url', 'display', 'name', 'account', 'description')
class ProviderNetworkSerializer(NetBoxModelSerializer): class ProviderNetworkSerializer(PrimaryModelSerializer):
provider = ProviderSerializer(nested=True) provider = ProviderSerializer(nested=True)
class Meta: class Meta:
model = ProviderNetwork model = ProviderNetwork
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'provider', 'name', 'service_id', 'description', 'comments', 'tags', 'id', 'url', 'display_url', 'display', 'provider', 'name', 'service_id', 'description', 'owner', 'comments',
'custom_fields', 'created', 'last_updated', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')

View File

@@ -6,7 +6,7 @@ from django.utils.translation import gettext as _
from dcim.filtersets import CabledObjectFilterSet from dcim.filtersets import CabledObjectFilterSet
from dcim.models import Interface, Location, Region, Site, SiteGroup from dcim.models import Interface, Location, Region, Site, SiteGroup
from ipam.models import ASN from ipam.models import ASN
from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet from netbox.filtersets import NetBoxModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet
from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
from utilities.filters import ( from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, TreeNodeMultipleChoiceFilter, ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter, TreeNodeMultipleChoiceFilter,
@@ -29,7 +29,7 @@ __all__ = (
) )
class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): class ProviderFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
region_id = TreeNodeMultipleChoiceFilter( region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='circuits__terminations___region', field_name='circuits__terminations___region',
@@ -95,7 +95,7 @@ class ProviderFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
) )
class ProviderAccountFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): class ProviderAccountFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter( provider_id = django_filters.ModelMultipleChoiceFilter(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
label=_('Provider (ID)'), label=_('Provider (ID)'),
@@ -122,7 +122,7 @@ class ProviderAccountFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
).distinct() ).distinct()
class ProviderNetworkFilterSet(NetBoxModelFilterSet): class ProviderNetworkFilterSet(PrimaryModelFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter( provider_id = django_filters.ModelMultipleChoiceFilter(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
label=_('Provider (ID)'), label=_('Provider (ID)'),
@@ -156,7 +156,7 @@ class CircuitTypeFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'color', 'description') fields = ('id', 'name', 'slug', 'color', 'description')
class CircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet): class CircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter( provider_id = django_filters.ModelMultipleChoiceFilter(
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
label=_('Provider (ID)'), label=_('Provider (ID)'),
@@ -475,7 +475,7 @@ class VirtualCircuitTypeFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'color', 'description') fields = ('id', 'name', 'slug', 'color', 'description')
class VirtualCircuitFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class VirtualCircuitFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
provider_id = django_filters.ModelMultipleChoiceFilter( provider_id = django_filters.ModelMultipleChoiceFilter(
field_name='provider_network__provider', field_name='provider_network__provider',
queryset=Provider.objects.all(), queryset=Provider.objects.all(),

View File

@@ -11,11 +11,11 @@ from circuits.models import *
from dcim.models import Site from dcim.models import Site
from ipam.models import ASN from ipam.models import ASN
from netbox.choices import DistanceUnitChoices from netbox.choices import DistanceUnitChoices
from netbox.forms import NetBoxModelBulkEditForm from netbox.forms import NetBoxModelBulkEditForm, OrganizationalModelBulkEditForm, PrimaryModelBulkEditForm
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms import add_blank_choice, get_field_value from utilities.forms import add_blank_choice, get_field_value
from utilities.forms.fields import ( from utilities.forms.fields import (
ColorField, CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, ColorField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
) )
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import BulkEditNullBooleanSelect, DatePicker, HTMXSelect, NumberWithOptions from utilities.forms.widgets import BulkEditNullBooleanSelect, DatePicker, HTMXSelect, NumberWithOptions
@@ -36,18 +36,12 @@ __all__ = (
) )
class ProviderBulkEditForm(NetBoxModelBulkEditForm): class ProviderBulkEditForm(PrimaryModelBulkEditForm):
asns = DynamicModelMultipleChoiceField( asns = DynamicModelMultipleChoiceField(
queryset=ASN.objects.all(), queryset=ASN.objects.all(),
label=_('ASNs'), label=_('ASNs'),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Provider model = Provider
fieldsets = ( fieldsets = (
@@ -58,18 +52,12 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm):
) )
class ProviderAccountBulkEditForm(NetBoxModelBulkEditForm): class ProviderAccountBulkEditForm(PrimaryModelBulkEditForm):
provider = DynamicModelChoiceField( provider = DynamicModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = ProviderAccount model = ProviderAccount
fieldsets = ( fieldsets = (
@@ -80,7 +68,7 @@ class ProviderAccountBulkEditForm(NetBoxModelBulkEditForm):
) )
class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm): class ProviderNetworkBulkEditForm(PrimaryModelBulkEditForm):
provider = DynamicModelChoiceField( provider = DynamicModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
@@ -91,12 +79,6 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
label=_('Service ID') label=_('Service ID')
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = ProviderNetwork model = ProviderNetwork
fieldsets = ( fieldsets = (
@@ -107,16 +89,11 @@ class ProviderNetworkBulkEditForm(NetBoxModelBulkEditForm):
) )
class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm): class CircuitTypeBulkEditForm(OrganizationalModelBulkEditForm):
color = ColorField( color = ColorField(
label=_('Color'), label=_('Color'),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = CircuitType model = CircuitType
fieldsets = ( fieldsets = (
@@ -125,7 +102,7 @@ class CircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('color', 'description') nullable_fields = ('color', 'description')
class CircuitBulkEditForm(NetBoxModelBulkEditForm): class CircuitBulkEditForm(PrimaryModelBulkEditForm):
type = DynamicModelChoiceField( type = DynamicModelChoiceField(
label=_('Type'), label=_('Type'),
queryset=CircuitType.objects.all(), queryset=CircuitType.objects.all(),
@@ -183,12 +160,6 @@ class CircuitBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
initial='' initial=''
) )
description = forms.CharField(
label=_('Description'),
max_length=100,
required=False
)
comments = CommentField()
model = Circuit model = Circuit
fieldsets = ( fieldsets = (
@@ -261,12 +232,7 @@ class CircuitTerminationBulkEditForm(NetBoxModelBulkEditForm):
pass pass
class CircuitGroupBulkEditForm(NetBoxModelBulkEditForm): class CircuitGroupBulkEditForm(OrganizationalModelBulkEditForm):
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
tenant = DynamicModelChoiceField( tenant = DynamicModelChoiceField(
label=_('Tenant'), label=_('Tenant'),
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@@ -298,16 +264,11 @@ class CircuitGroupAssignmentBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('priority',) nullable_fields = ('priority',)
class VirtualCircuitTypeBulkEditForm(NetBoxModelBulkEditForm): class VirtualCircuitTypeBulkEditForm(OrganizationalModelBulkEditForm):
color = ColorField( color = ColorField(
label=_('Color'), label=_('Color'),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = VirtualCircuitType model = VirtualCircuitType
fieldsets = ( fieldsets = (
@@ -316,7 +277,7 @@ class VirtualCircuitTypeBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('color', 'description') nullable_fields = ('color', 'description')
class VirtualCircuitBulkEditForm(NetBoxModelBulkEditForm): class VirtualCircuitBulkEditForm(PrimaryModelBulkEditForm):
provider_network = DynamicModelChoiceField( provider_network = DynamicModelChoiceField(
label=_('Provider network'), label=_('Provider network'),
queryset=ProviderNetwork.objects.all(), queryset=ProviderNetwork.objects.all(),
@@ -343,12 +304,6 @@ class VirtualCircuitBulkEditForm(NetBoxModelBulkEditForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=100,
required=False
)
comments = CommentField()
model = VirtualCircuit model = VirtualCircuit
fieldsets = ( fieldsets = (

View File

@@ -7,7 +7,7 @@ from circuits.constants import *
from circuits.models import * from circuits.models import *
from dcim.models import Interface from dcim.models import Interface
from netbox.choices import DistanceUnitChoices from netbox.choices import DistanceUnitChoices
from netbox.forms import NetBoxModelImportForm from netbox.forms import NetBoxModelImportForm, OrganizationalModelImportForm, PrimaryModelImportForm
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms.fields import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, SlugField from utilities.forms.fields import CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, SlugField
@@ -28,17 +28,17 @@ __all__ = (
) )
class ProviderImportForm(NetBoxModelImportForm): class ProviderImportForm(PrimaryModelImportForm):
slug = SlugField() slug = SlugField()
class Meta: class Meta:
model = Provider model = Provider
fields = ( fields = (
'name', 'slug', 'description', 'comments', 'tags', 'name', 'slug', 'description', 'owner', 'comments', 'tags',
) )
class ProviderAccountImportForm(NetBoxModelImportForm): class ProviderAccountImportForm(PrimaryModelImportForm):
provider = CSVModelChoiceField( provider = CSVModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
@@ -49,11 +49,11 @@ class ProviderAccountImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ProviderAccount model = ProviderAccount
fields = ( fields = (
'provider', 'name', 'account', 'description', 'comments', 'tags', 'provider', 'name', 'account', 'description', 'owner', 'comments', 'tags',
) )
class ProviderNetworkImportForm(NetBoxModelImportForm): class ProviderNetworkImportForm(PrimaryModelImportForm):
provider = CSVModelChoiceField( provider = CSVModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
@@ -64,19 +64,19 @@ class ProviderNetworkImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ProviderNetwork model = ProviderNetwork
fields = [ fields = [
'provider', 'name', 'service_id', 'description', 'comments', 'tags' 'provider', 'name', 'service_id', 'description', 'owner', 'comments', 'tags'
] ]
class CircuitTypeImportForm(NetBoxModelImportForm): class CircuitTypeImportForm(OrganizationalModelImportForm):
slug = SlugField() slug = SlugField()
class Meta: class Meta:
model = CircuitType model = CircuitType
fields = ('name', 'slug', 'color', 'description', 'tags') fields = ('name', 'slug', 'color', 'description', 'owner', 'tags')
class CircuitImportForm(NetBoxModelImportForm): class CircuitImportForm(PrimaryModelImportForm):
provider = CSVModelChoiceField( provider = CSVModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
@@ -119,7 +119,7 @@ class CircuitImportForm(NetBoxModelImportForm):
model = Circuit model = Circuit
fields = [ fields = [
'cid', 'provider', 'provider_account', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'cid', 'provider', 'provider_account', 'type', 'status', 'tenant', 'install_date', 'termination_date',
'commit_rate', 'distance', 'distance_unit', 'description', 'comments', 'tags' 'commit_rate', 'distance', 'distance_unit', 'description', 'owner', 'comments', 'tags'
] ]
@@ -165,7 +165,7 @@ class CircuitTerminationImportForm(NetBoxModelImportForm, BaseCircuitTermination
} }
class CircuitGroupImportForm(NetBoxModelImportForm): class CircuitGroupImportForm(OrganizationalModelImportForm):
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
label=_('Tenant'), label=_('Tenant'),
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@@ -176,7 +176,7 @@ class CircuitGroupImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = CircuitGroup model = CircuitGroup
fields = ('name', 'slug', 'description', 'tenant', 'tags') fields = ('name', 'slug', 'description', 'tenant', 'owner', 'tags')
class CircuitGroupAssignmentImportForm(NetBoxModelImportForm): class CircuitGroupAssignmentImportForm(NetBoxModelImportForm):
@@ -195,15 +195,14 @@ class CircuitGroupAssignmentImportForm(NetBoxModelImportForm):
fields = ('member_type', 'member_id', 'group', 'priority') fields = ('member_type', 'member_id', 'group', 'priority')
class VirtualCircuitTypeImportForm(NetBoxModelImportForm): class VirtualCircuitTypeImportForm(OrganizationalModelImportForm):
slug = SlugField()
class Meta: class Meta:
model = VirtualCircuitType model = VirtualCircuitType
fields = ('name', 'slug', 'color', 'description', 'tags') fields = ('name', 'slug', 'color', 'description', 'owner', 'tags')
class VirtualCircuitImportForm(NetBoxModelImportForm): class VirtualCircuitImportForm(PrimaryModelImportForm):
provider_network = CSVModelChoiceField( provider_network = CSVModelChoiceField(
label=_('Provider network'), label=_('Provider network'),
queryset=ProviderNetwork.objects.all(), queryset=ProviderNetwork.objects.all(),
@@ -239,8 +238,8 @@ class VirtualCircuitImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = VirtualCircuit model = VirtualCircuit
fields = [ fields = [
'cid', 'provider_network', 'provider_account', 'type', 'status', 'tenant', 'description', 'comments', 'cid', 'provider_network', 'provider_account', 'type', 'status', 'tenant', 'description', 'owner',
'tags', 'comments', 'tags',
] ]

View File

@@ -9,7 +9,7 @@ from circuits.models import *
from dcim.models import Location, Region, Site, SiteGroup from dcim.models import Location, Region, Site, SiteGroup
from ipam.models import ASN from ipam.models import ASN
from netbox.choices import DistanceUnitChoices from netbox.choices import DistanceUnitChoices
from netbox.forms import NetBoxModelFilterSetForm from netbox.forms import NetBoxModelFilterSetForm, OrganizationalModelFilterSetForm, PrimaryModelFilterSetForm
from tenancy.forms import TenancyFilterForm, ContactModelFilterForm from tenancy.forms import TenancyFilterForm, ContactModelFilterForm
from utilities.forms import add_blank_choice from utilities.forms import add_blank_choice
from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, TagFilterField from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, TagFilterField
@@ -31,10 +31,10 @@ __all__ = (
) )
class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): class ProviderFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
model = Provider model = Provider
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
FieldSet('asn_id', name=_('ASN')), FieldSet('asn_id', name=_('ASN')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
@@ -66,10 +66,10 @@ class ProviderFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class ProviderAccountFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): class ProviderAccountFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
model = ProviderAccount model = ProviderAccount
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('provider_id', 'account', name=_('Attributes')), FieldSet('provider_id', 'account', name=_('Attributes')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
@@ -85,10 +85,10 @@ class ProviderAccountFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm
tag = TagFilterField(model) tag = TagFilterField(model)
class ProviderNetworkFilterForm(NetBoxModelFilterSetForm): class ProviderNetworkFilterForm(PrimaryModelFilterSetForm):
model = ProviderNetwork model = ProviderNetwork
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('provider_id', 'service_id', name=_('Attributes')), FieldSet('provider_id', 'service_id', name=_('Attributes')),
) )
provider_id = DynamicModelMultipleChoiceField( provider_id = DynamicModelMultipleChoiceField(
@@ -104,10 +104,10 @@ class ProviderNetworkFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class CircuitTypeFilterForm(NetBoxModelFilterSetForm): class CircuitTypeFilterForm(OrganizationalModelFilterSetForm):
model = CircuitType model = CircuitType
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('color', name=_('Attributes')), FieldSet('color', name=_('Attributes')),
) )
tag = TagFilterField(model) tag = TagFilterField(model)
@@ -118,10 +118,10 @@ class CircuitTypeFilterForm(NetBoxModelFilterSetForm):
) )
class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm): class CircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
model = Circuit model = Circuit
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')), FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')),
FieldSet( FieldSet(
'type_id', 'status', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit', 'type_id', 'status', 'install_date', 'termination_date', 'commit_rate', 'distance', 'distance_unit',
@@ -271,10 +271,10 @@ class CircuitTerminationFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class CircuitGroupFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class CircuitGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
model = CircuitGroup model = CircuitGroup
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
) )
tag = TagFilterField(model) tag = TagFilterField(model)
@@ -309,10 +309,10 @@ class CircuitGroupAssignmentFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class VirtualCircuitTypeFilterForm(NetBoxModelFilterSetForm): class VirtualCircuitTypeFilterForm(OrganizationalModelFilterSetForm):
model = VirtualCircuitType model = VirtualCircuitType
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('color', name=_('Attributes')), FieldSet('color', name=_('Attributes')),
) )
tag = TagFilterField(model) tag = TagFilterField(model)
@@ -323,10 +323,10 @@ class VirtualCircuitTypeFilterForm(NetBoxModelFilterSetForm):
) )
class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm): class VirtualCircuitFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
model = VirtualCircuit model = VirtualCircuit
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')), FieldSet('provider_id', 'provider_account_id', 'provider_network_id', name=_('Provider')),
FieldSet('type_id', 'status', name=_('Attributes')), FieldSet('type_id', 'status', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),

View File

@@ -10,11 +10,11 @@ from circuits.constants import *
from circuits.models import * from circuits.models import *
from dcim.models import Interface, Site from dcim.models import Interface, Site
from ipam.models import ASN from ipam.models import ASN
from netbox.forms import NetBoxModelForm from netbox.forms import NetBoxModelForm, OrganizationalModelForm, PrimaryModelForm
from tenancy.forms import TenancyForm from tenancy.forms import TenancyForm
from utilities.forms import get_field_value from utilities.forms import get_field_value
from utilities.forms.fields import ( from utilities.forms.fields import (
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField,
) )
from utilities.forms.mixins import DistanceValidationMixin from utilities.forms.mixins import DistanceValidationMixin
from utilities.forms.rendering import FieldSet, InlineFields from utilities.forms.rendering import FieldSet, InlineFields
@@ -36,14 +36,13 @@ __all__ = (
) )
class ProviderForm(NetBoxModelForm): class ProviderForm(PrimaryModelForm):
slug = SlugField() slug = SlugField()
asns = DynamicModelMultipleChoiceField( asns = DynamicModelMultipleChoiceField(
queryset=ASN.objects.all(), queryset=ASN.objects.all(),
label=_('ASNs'), label=_('ASNs'),
required=False required=False
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'asns', 'description', 'tags'), FieldSet('name', 'slug', 'asns', 'description', 'tags'),
@@ -52,34 +51,32 @@ class ProviderForm(NetBoxModelForm):
class Meta: class Meta:
model = Provider model = Provider
fields = [ fields = [
'name', 'slug', 'asns', 'description', 'comments', 'tags', 'name', 'slug', 'asns', 'description', 'owner', 'comments', 'tags',
] ]
class ProviderAccountForm(NetBoxModelForm): class ProviderAccountForm(PrimaryModelForm):
provider = DynamicModelChoiceField( provider = DynamicModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
selector=True, selector=True,
quick_add=True quick_add=True
) )
comments = CommentField()
class Meta: class Meta:
model = ProviderAccount model = ProviderAccount
fields = [ fields = [
'provider', 'name', 'account', 'description', 'comments', 'tags', 'provider', 'name', 'account', 'description', 'owner', 'comments', 'tags',
] ]
class ProviderNetworkForm(NetBoxModelForm): class ProviderNetworkForm(PrimaryModelForm):
provider = DynamicModelChoiceField( provider = DynamicModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
selector=True, selector=True,
quick_add=True quick_add=True
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('provider', 'name', 'service_id', 'description', 'tags'), FieldSet('provider', 'name', 'service_id', 'description', 'tags'),
@@ -88,15 +85,13 @@ class ProviderNetworkForm(NetBoxModelForm):
class Meta: class Meta:
model = ProviderNetwork model = ProviderNetwork
fields = [ fields = [
'provider', 'name', 'service_id', 'description', 'comments', 'tags', 'provider', 'name', 'service_id', 'description', 'owner', 'comments', 'tags',
] ]
class CircuitTypeForm(NetBoxModelForm): class CircuitTypeForm(OrganizationalModelForm):
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'color', 'description', 'tags'), FieldSet('name', 'slug', 'color', 'description', 'owner', 'tags'),
) )
class Meta: class Meta:
@@ -106,7 +101,7 @@ class CircuitTypeForm(NetBoxModelForm):
] ]
class CircuitForm(DistanceValidationMixin, TenancyForm, NetBoxModelForm): class CircuitForm(DistanceValidationMixin, TenancyForm, PrimaryModelForm):
provider = DynamicModelChoiceField( provider = DynamicModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),
@@ -125,7 +120,6 @@ class CircuitForm(DistanceValidationMixin, TenancyForm, NetBoxModelForm):
queryset=CircuitType.objects.all(), queryset=CircuitType.objects.all(),
quick_add=True quick_add=True
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -147,7 +141,7 @@ class CircuitForm(DistanceValidationMixin, TenancyForm, NetBoxModelForm):
model = Circuit model = Circuit
fields = [ fields = [
'cid', 'type', 'provider', 'provider_account', 'status', 'install_date', 'termination_date', 'commit_rate', 'cid', 'type', 'provider', 'provider_account', 'status', 'install_date', 'termination_date', 'commit_rate',
'distance', 'distance_unit', 'description', 'tenant_group', 'tenant', 'comments', 'tags', 'distance', 'distance_unit', 'description', 'tenant_group', 'tenant', 'owner', 'comments', 'tags',
] ]
widgets = { widgets = {
'install_date': DatePicker(), 'install_date': DatePicker(),
@@ -233,9 +227,7 @@ class CircuitTerminationForm(NetBoxModelForm):
self.instance.termination = self.cleaned_data.get('termination') self.instance.termination = self.cleaned_data.get('termination')
class CircuitGroupForm(TenancyForm, NetBoxModelForm): class CircuitGroupForm(TenancyForm, OrganizationalModelForm):
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'description', 'tags', name=_('Circuit Group')), FieldSet('name', 'slug', 'description', 'tags', name=_('Circuit Group')),
FieldSet('tenant_group', 'tenant', name=_('Tenancy')), FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
@@ -244,7 +236,7 @@ class CircuitGroupForm(TenancyForm, NetBoxModelForm):
class Meta: class Meta:
model = CircuitGroup model = CircuitGroup
fields = [ fields = [
'name', 'slug', 'description', 'tenant_group', 'tenant', 'tags', 'name', 'slug', 'description', 'tenant_group', 'tenant', 'owner', 'tags',
] ]
@@ -307,9 +299,7 @@ class CircuitGroupAssignmentForm(NetBoxModelForm):
self.instance.member = self.cleaned_data.get('member') self.instance.member = self.cleaned_data.get('member')
class VirtualCircuitTypeForm(NetBoxModelForm): class VirtualCircuitTypeForm(OrganizationalModelForm):
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'color', 'description', 'tags'), FieldSet('name', 'slug', 'color', 'description', 'tags'),
) )
@@ -317,11 +307,11 @@ class VirtualCircuitTypeForm(NetBoxModelForm):
class Meta: class Meta:
model = VirtualCircuitType model = VirtualCircuitType
fields = [ fields = [
'name', 'slug', 'color', 'description', 'tags', 'name', 'slug', 'color', 'description', 'owner', 'tags',
] ]
class VirtualCircuitForm(TenancyForm, NetBoxModelForm): class VirtualCircuitForm(TenancyForm, PrimaryModelForm):
provider_network = DynamicModelChoiceField( provider_network = DynamicModelChoiceField(
label=_('Provider network'), label=_('Provider network'),
queryset=ProviderNetwork.objects.all(), queryset=ProviderNetwork.objects.all(),
@@ -336,7 +326,6 @@ class VirtualCircuitForm(TenancyForm, NetBoxModelForm):
queryset=VirtualCircuitType.objects.all(), queryset=VirtualCircuitType.objects.all(),
quick_add=True quick_add=True
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -350,7 +339,7 @@ class VirtualCircuitForm(TenancyForm, NetBoxModelForm):
model = VirtualCircuit model = VirtualCircuit
fields = [ fields = [
'cid', 'provider_network', 'provider_account', 'type', 'status', 'description', 'tenant_group', 'tenant', 'cid', 'provider_network', 'provider_account', 'type', 'status', 'description', 'tenant_group', 'tenant',
'comments', 'tags', 'owner', 'comments', 'tags',
] ]

View File

@@ -6,7 +6,7 @@ import strawberry_django
from circuits import models from circuits import models
from dcim.graphql.mixins import CabledObjectMixin from dcim.graphql.mixins import CabledObjectMixin
from extras.graphql.mixins import ContactsMixin, CustomFieldsMixin, TagsMixin from extras.graphql.mixins import ContactsMixin, CustomFieldsMixin, TagsMixin
from netbox.graphql.types import BaseObjectType, NetBoxObjectType, ObjectType, OrganizationalObjectType from netbox.graphql.types import BaseObjectType, ObjectType, OrganizationalObjectType, PrimaryObjectType
from tenancy.graphql.types import TenantType from tenancy.graphql.types import TenantType
from .filters import * from .filters import *
@@ -35,8 +35,7 @@ __all__ = (
filters=ProviderFilter, filters=ProviderFilter,
pagination=True pagination=True
) )
class ProviderType(NetBoxObjectType, ContactsMixin): class ProviderType(ContactsMixin, PrimaryObjectType):
networks: List[Annotated["ProviderNetworkType", strawberry.lazy('circuits.graphql.types')]] networks: List[Annotated["ProviderNetworkType", strawberry.lazy('circuits.graphql.types')]]
circuits: List[Annotated["CircuitType", strawberry.lazy('circuits.graphql.types')]] circuits: List[Annotated["CircuitType", strawberry.lazy('circuits.graphql.types')]]
asns: List[Annotated["ASNType", strawberry.lazy('ipam.graphql.types')]] asns: List[Annotated["ASNType", strawberry.lazy('ipam.graphql.types')]]
@@ -49,9 +48,8 @@ class ProviderType(NetBoxObjectType, ContactsMixin):
filters=ProviderAccountFilter, filters=ProviderAccountFilter,
pagination=True pagination=True
) )
class ProviderAccountType(ContactsMixin, NetBoxObjectType): class ProviderAccountType(ContactsMixin, PrimaryObjectType):
provider: Annotated["ProviderType", strawberry.lazy('circuits.graphql.types')] provider: Annotated["ProviderType", strawberry.lazy('circuits.graphql.types')]
circuits: List[Annotated["CircuitType", strawberry.lazy('circuits.graphql.types')]] circuits: List[Annotated["CircuitType", strawberry.lazy('circuits.graphql.types')]]
@@ -61,9 +59,8 @@ class ProviderAccountType(ContactsMixin, NetBoxObjectType):
filters=ProviderNetworkFilter, filters=ProviderNetworkFilter,
pagination=True pagination=True
) )
class ProviderNetworkType(NetBoxObjectType): class ProviderNetworkType(PrimaryObjectType):
provider: Annotated["ProviderType", strawberry.lazy('circuits.graphql.types')] provider: Annotated["ProviderType", strawberry.lazy('circuits.graphql.types')]
circuit_terminations: List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]] circuit_terminations: List[Annotated["CircuitTerminationType", strawberry.lazy('circuits.graphql.types')]]
@@ -105,14 +102,13 @@ class CircuitTypeType(OrganizationalObjectType):
filters=CircuitFilter, filters=CircuitFilter,
pagination=True pagination=True
) )
class CircuitType(NetBoxObjectType, ContactsMixin): class CircuitType(PrimaryObjectType, ContactsMixin):
provider: ProviderType provider: ProviderType
provider_account: ProviderAccountType | None provider_account: ProviderAccountType | None
termination_a: CircuitTerminationType | None termination_a: CircuitTerminationType | None
termination_z: CircuitTerminationType | None termination_z: CircuitTerminationType | None
type: CircuitTypeType type: CircuitTypeType
tenant: TenantType | None tenant: TenantType | None
terminations: List[CircuitTerminationType] terminations: List[CircuitTerminationType]
@@ -178,12 +174,11 @@ class VirtualCircuitTerminationType(CustomFieldsMixin, TagsMixin, ObjectType):
filters=VirtualCircuitFilter, filters=VirtualCircuitFilter,
pagination=True pagination=True
) )
class VirtualCircuitType(NetBoxObjectType): class VirtualCircuitType(PrimaryObjectType):
provider_network: ProviderNetworkType = strawberry_django.field(select_related=["provider_network"]) provider_network: ProviderNetworkType = strawberry_django.field(select_related=["provider_network"])
provider_account: ProviderAccountType | None provider_account: ProviderAccountType | None
type: Annotated["VirtualCircuitTypeType", strawberry.lazy('circuits.graphql.types')] = strawberry_django.field( type: Annotated["VirtualCircuitTypeType", strawberry.lazy('circuits.graphql.types')] = strawberry_django.field(
select_related=["type"] select_related=["type"]
) )
tenant: TenantType | None tenant: TenantType | None
terminations: List[VirtualCircuitTerminationType] terminations: List[VirtualCircuitTerminationType]

View File

@@ -0,0 +1,68 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('circuits', '0052_extend_circuit_abs_distance_upper_limit'),
('users', '0015_owner'),
]
operations = [
migrations.AddField(
model_name='circuit',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='circuitgroup',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='circuittype',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='provider',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='provideraccount',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='providernetwork',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='virtualcircuit',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='virtualcircuittype',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
]

View File

@@ -1,11 +1,9 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from circuits.models import * from circuits.models import *
from netbox.tables import NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from netbox.tables import NetBoxTable, columns
from .columns import CommitRateColumn from .columns import CommitRateColumn
__all__ = ( __all__ = (
@@ -24,7 +22,7 @@ CIRCUITTERMINATION_LINK = """
""" """
class CircuitTypeTable(NetBoxTable): class CircuitTypeTable(OrganizationalModelTable):
name = tables.Column( name = tables.Column(
linkify=True, linkify=True,
verbose_name=_('Name'), verbose_name=_('Name'),
@@ -39,7 +37,7 @@ class CircuitTypeTable(NetBoxTable):
verbose_name=_('Circuits') verbose_name=_('Circuits')
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = CircuitType model = CircuitType
fields = ( fields = (
'pk', 'id', 'name', 'circuit_count', 'color', 'description', 'slug', 'tags', 'created', 'last_updated', 'pk', 'id', 'name', 'circuit_count', 'color', 'description', 'slug', 'tags', 'created', 'last_updated',
@@ -48,7 +46,7 @@ class CircuitTypeTable(NetBoxTable):
default_columns = ('pk', 'name', 'circuit_count', 'color', 'description') default_columns = ('pk', 'name', 'circuit_count', 'color', 'description')
class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModelTable):
cid = tables.Column( cid = tables.Column(
linkify=True, linkify=True,
verbose_name=_('Circuit ID') verbose_name=_('Circuit ID')
@@ -79,9 +77,6 @@ class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
verbose_name=_('Commit Rate') verbose_name=_('Commit Rate')
) )
distance = columns.DistanceColumn() distance = columns.DistanceColumn()
comments = columns.MarkdownColumn(
verbose_name=_('Comments')
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='circuits:circuit_list' url_name='circuits:circuit_list'
) )
@@ -90,7 +85,7 @@ class CircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
linkify_item=True linkify_item=True
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Circuit model = Circuit
fields = ( fields = (
'pk', 'id', 'cid', 'provider', 'provider_account', 'type', 'status', 'tenant', 'tenant_group', 'pk', 'id', 'cid', 'provider', 'provider_account', 'type', 'status', 'tenant', 'tenant_group',
@@ -163,7 +158,7 @@ class CircuitTerminationTable(NetBoxTable):
) )
class CircuitGroupTable(NetBoxTable): class CircuitGroupTable(OrganizationalModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -177,7 +172,7 @@ class CircuitGroupTable(NetBoxTable):
url_name='circuits:circuitgroup_list' url_name='circuits:circuitgroup_list'
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = CircuitGroup model = CircuitGroup
fields = ( fields = (
'pk', 'name', 'description', 'circuit_group_assignment_count', 'tags', 'pk', 'name', 'description', 'circuit_group_assignment_count', 'tags',

View File

@@ -1,10 +1,10 @@
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from circuits.models import *
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from tenancy.tables import ContactsColumnMixin
from netbox.tables import NetBoxTable, columns from circuits.models import *
from netbox.tables import PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin
__all__ = ( __all__ = (
'ProviderTable', 'ProviderTable',
@@ -13,7 +13,7 @@ __all__ = (
) )
class ProviderTable(ContactsColumnMixin, NetBoxTable): class ProviderTable(ContactsColumnMixin, PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -42,14 +42,11 @@ class ProviderTable(ContactsColumnMixin, NetBoxTable):
url_params={'provider_id': 'pk'}, url_params={'provider_id': 'pk'},
verbose_name=_('Circuits') verbose_name=_('Circuits')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='circuits:provider_list' url_name='circuits:provider_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Provider model = Provider
fields = ( fields = (
'pk', 'id', 'name', 'accounts', 'account_count', 'asns', 'asn_count', 'circuit_count', 'description', 'pk', 'id', 'name', 'accounts', 'account_count', 'asns', 'asn_count', 'circuit_count', 'description',
@@ -58,7 +55,7 @@ class ProviderTable(ContactsColumnMixin, NetBoxTable):
default_columns = ('pk', 'name', 'account_count', 'circuit_count') default_columns = ('pk', 'name', 'account_count', 'circuit_count')
class ProviderAccountTable(ContactsColumnMixin, NetBoxTable): class ProviderAccountTable(ContactsColumnMixin, PrimaryModelTable):
account = tables.Column( account = tables.Column(
linkify=True, linkify=True,
verbose_name=_('Account'), verbose_name=_('Account'),
@@ -76,14 +73,11 @@ class ProviderAccountTable(ContactsColumnMixin, NetBoxTable):
url_params={'provider_account_id': 'pk'}, url_params={'provider_account_id': 'pk'},
verbose_name=_('Circuits') verbose_name=_('Circuits')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='circuits:provideraccount_list' url_name='circuits:provideraccount_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = ProviderAccount model = ProviderAccount
fields = ( fields = (
'pk', 'id', 'account', 'name', 'provider', 'circuit_count', 'comments', 'contacts', 'tags', 'created', 'pk', 'id', 'account', 'name', 'provider', 'circuit_count', 'comments', 'contacts', 'tags', 'created',
@@ -92,7 +86,7 @@ class ProviderAccountTable(ContactsColumnMixin, NetBoxTable):
default_columns = ('pk', 'account', 'name', 'provider', 'circuit_count') default_columns = ('pk', 'account', 'name', 'provider', 'circuit_count')
class ProviderNetworkTable(NetBoxTable): class ProviderNetworkTable(PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -101,14 +95,11 @@ class ProviderNetworkTable(NetBoxTable):
verbose_name=_('Provider'), verbose_name=_('Provider'),
linkify=True linkify=True
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='circuits:providernetwork_list' url_name='circuits:providernetwork_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = ProviderNetwork model = ProviderNetwork
fields = ( fields = (
'pk', 'id', 'name', 'provider', 'service_id', 'description', 'comments', 'created', 'last_updated', 'tags', 'pk', 'id', 'name', 'provider', 'service_id', 'description', 'comments', 'created', 'last_updated', 'tags',

View File

@@ -2,7 +2,7 @@ import django_tables2 as tables
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from circuits.models import * from circuits.models import *
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
__all__ = ( __all__ = (
@@ -12,7 +12,7 @@ __all__ = (
) )
class VirtualCircuitTypeTable(NetBoxTable): class VirtualCircuitTypeTable(OrganizationalModelTable):
name = tables.Column( name = tables.Column(
linkify=True, linkify=True,
verbose_name=_('Name'), verbose_name=_('Name'),
@@ -27,7 +27,7 @@ class VirtualCircuitTypeTable(NetBoxTable):
verbose_name=_('Circuits') verbose_name=_('Circuits')
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = VirtualCircuitType model = VirtualCircuitType
fields = ( fields = (
'pk', 'id', 'name', 'virtual_circuit_count', 'color', 'description', 'slug', 'tags', 'created', 'pk', 'id', 'name', 'virtual_circuit_count', 'color', 'description', 'slug', 'tags', 'created',
@@ -36,7 +36,7 @@ class VirtualCircuitTypeTable(NetBoxTable):
default_columns = ('pk', 'name', 'virtual_circuit_count', 'color', 'description') default_columns = ('pk', 'name', 'virtual_circuit_count', 'color', 'description')
class VirtualCircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): class VirtualCircuitTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModelTable):
cid = tables.Column( cid = tables.Column(
linkify=True, linkify=True,
verbose_name=_('Circuit ID') verbose_name=_('Circuit ID')
@@ -63,14 +63,11 @@ class VirtualCircuitTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable)
url_params={'virtual_circuit_id': 'pk'}, url_params={'virtual_circuit_id': 'pk'},
verbose_name=_('Terminations') verbose_name=_('Terminations')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments')
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='circuits:virtualcircuit_list' url_name='circuits:virtualcircuit_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = VirtualCircuit model = VirtualCircuit
fields = ( fields = (
'pk', 'id', 'cid', 'provider', 'provider_account', 'provider_network', 'type', 'status', 'tenant', 'pk', 'id', 'cid', 'provider', 'provider_account', 'provider_network', 'type', 'status', 'tenant',

View File

@@ -1,7 +1,7 @@
from core.choices import * from core.choices import *
from core.models import DataFile, DataSource from core.models import DataFile, DataSource
from netbox.api.fields import ChoiceField, RelatedObjectCountField from netbox.api.fields import ChoiceField, RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer, PrimaryModelSerializer
from netbox.utils import get_data_backend_choices from netbox.utils import get_data_backend_choices
__all__ = ( __all__ = (
@@ -10,7 +10,7 @@ __all__ = (
) )
class DataSourceSerializer(NetBoxModelSerializer): class DataSourceSerializer(PrimaryModelSerializer):
type = ChoiceField( type = ChoiceField(
choices=get_data_backend_choices() choices=get_data_backend_choices()
) )
@@ -26,8 +26,8 @@ class DataSourceSerializer(NetBoxModelSerializer):
model = DataSource model = DataSource
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'type', 'source_url', 'enabled', 'status', 'description', 'id', 'url', 'display_url', 'display', 'name', 'type', 'source_url', 'enabled', 'status', 'description',
'sync_interval', 'parameters', 'ignore_rules', 'comments', 'custom_fields', 'created', 'last_updated', 'sync_interval', 'parameters', 'ignore_rules', 'owner', 'comments', 'custom_fields', 'created',
'last_synced', 'file_count', 'last_updated', 'last_synced', 'file_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')

View File

@@ -3,7 +3,7 @@ from django.contrib.contenttypes.models import ContentType
from django.db.models import Q from django.db.models import Q
from django.utils.translation import gettext as _ from django.utils.translation import gettext as _
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, PrimaryModelFilterSet
from netbox.utils import get_data_backend_choices from netbox.utils import get_data_backend_choices
from users.models import User from users.models import User
from utilities.filters import ContentTypeFilter from utilities.filters import ContentTypeFilter
@@ -20,7 +20,7 @@ __all__ = (
) )
class DataSourceFilterSet(NetBoxModelFilterSet): class DataSourceFilterSet(PrimaryModelFilterSet):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=get_data_backend_choices, choices=get_data_backend_choices,
null_value=None null_value=None

View File

@@ -3,9 +3,8 @@ from django.utils.translation import gettext_lazy as _
from core.choices import JobIntervalChoices from core.choices import JobIntervalChoices
from core.models import * from core.models import *
from netbox.forms import NetBoxModelBulkEditForm from netbox.forms import PrimaryModelBulkEditForm
from netbox.utils import get_data_backend_choices from netbox.utils import get_data_backend_choices
from utilities.forms.fields import CommentField
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import BulkEditNullBooleanSelect from utilities.forms.widgets import BulkEditNullBooleanSelect
@@ -14,7 +13,7 @@ __all__ = (
) )
class DataSourceBulkEditForm(NetBoxModelBulkEditForm): class DataSourceBulkEditForm(PrimaryModelBulkEditForm):
type = forms.ChoiceField( type = forms.ChoiceField(
label=_('Type'), label=_('Type'),
choices=get_data_backend_choices, choices=get_data_backend_choices,
@@ -25,17 +24,11 @@ class DataSourceBulkEditForm(NetBoxModelBulkEditForm):
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label=_('Enabled') label=_('Enabled')
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
sync_interval = forms.ChoiceField( sync_interval = forms.ChoiceField(
choices=JobIntervalChoices, choices=JobIntervalChoices,
required=False, required=False,
label=_('Sync interval') label=_('Sync interval')
) )
comments = CommentField()
parameters = forms.JSONField( parameters = forms.JSONField(
label=_('Parameters'), label=_('Parameters'),
required=False required=False

View File

@@ -1,16 +1,16 @@
from core.models import * from core.models import *
from netbox.forms import NetBoxModelImportForm from netbox.forms import PrimaryModelImportForm
__all__ = ( __all__ = (
'DataSourceImportForm', 'DataSourceImportForm',
) )
class DataSourceImportForm(NetBoxModelImportForm): class DataSourceImportForm(PrimaryModelImportForm):
class Meta: class Meta:
model = DataSource model = DataSource
fields = ( fields = (
'name', 'type', 'source_url', 'enabled', 'description', 'sync_interval', 'parameters', 'ignore_rules', 'name', 'type', 'source_url', 'enabled', 'description', 'sync_interval', 'parameters', 'ignore_rules',
'comments', 'owner', 'comments',
) )

View File

@@ -3,13 +3,13 @@ from django.utils.translation import gettext_lazy as _
from core.choices import * from core.choices import *
from core.models import * from core.models import *
from netbox.forms import NetBoxModelFilterSetForm from netbox.forms import NetBoxModelFilterSetForm, PrimaryModelFilterSetForm
from netbox.forms.mixins import SavedFiltersMixin from netbox.forms.mixins import SavedFiltersMixin
from netbox.utils import get_data_backend_choices from netbox.utils import get_data_backend_choices
from users.models import User from users.models import User
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
from utilities.forms.fields import ( from utilities.forms.fields import (
ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, TagFilterField,
) )
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import DateTimePicker from utilities.forms.widgets import DateTimePicker
@@ -23,10 +23,10 @@ __all__ = (
) )
class DataSourceFilterForm(NetBoxModelFilterSetForm): class DataSourceFilterForm(PrimaryModelFilterSetForm):
model = DataSource model = DataSource
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('type', 'status', 'enabled', 'sync_interval', name=_('Data Source')), FieldSet('type', 'status', 'enabled', 'sync_interval', name=_('Data Source')),
) )
type = forms.MultipleChoiceField( type = forms.MultipleChoiceField(
@@ -51,6 +51,7 @@ class DataSourceFilterForm(NetBoxModelFilterSetForm):
choices=JobIntervalChoices, choices=JobIntervalChoices,
required=False required=False
) )
tag = TagFilterField(model)
class DataFileFilterForm(NetBoxModelFilterSetForm): class DataFileFilterForm(NetBoxModelFilterSetForm):

View File

@@ -9,11 +9,11 @@ from django.utils.translation import gettext_lazy as _
from core.forms.mixins import SyncedDataMixin from core.forms.mixins import SyncedDataMixin
from core.models import * from core.models import *
from netbox.config import get_config, PARAMS from netbox.config import get_config, PARAMS
from netbox.forms import NetBoxModelForm from netbox.forms import NetBoxModelForm, PrimaryModelForm
from netbox.registry import registry from netbox.registry import registry
from netbox.utils import get_data_backend_choices from netbox.utils import get_data_backend_choices
from utilities.forms import get_field_value from utilities.forms import get_field_value
from utilities.forms.fields import CommentField, JSONField from utilities.forms.fields import JSONField
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import HTMXSelect from utilities.forms.widgets import HTMXSelect
@@ -26,17 +26,17 @@ __all__ = (
EMPTY_VALUES = ('', None, [], ()) EMPTY_VALUES = ('', None, [], ())
class DataSourceForm(NetBoxModelForm): class DataSourceForm(PrimaryModelForm):
type = forms.ChoiceField( type = forms.ChoiceField(
choices=get_data_backend_choices, choices=get_data_backend_choices,
widget=HTMXSelect() widget=HTMXSelect()
) )
comments = CommentField()
class Meta: class Meta:
model = DataSource model = DataSource
fields = [ fields = [
'name', 'type', 'source_url', 'enabled', 'description', 'sync_interval', 'ignore_rules', 'comments', 'tags', 'name', 'type', 'source_url', 'enabled', 'description', 'sync_interval', 'ignore_rules', 'owner',
'comments', 'tags',
] ]
widgets = { widgets = {
'ignore_rules': forms.Textarea( 'ignore_rules': forms.Textarea(

View File

@@ -5,7 +5,7 @@ import strawberry_django
from django.contrib.contenttypes.models import ContentType as DjangoContentType from django.contrib.contenttypes.models import ContentType as DjangoContentType
from core import models from core import models
from netbox.graphql.types import BaseObjectType, NetBoxObjectType from netbox.graphql.types import BaseObjectType, PrimaryObjectType
from .filters import * from .filters import *
__all__ = ( __all__ = (
@@ -32,8 +32,7 @@ class DataFileType(BaseObjectType):
filters=DataSourceFilter, filters=DataSourceFilter,
pagination=True pagination=True
) )
class DataSourceType(NetBoxObjectType): class DataSourceType(PrimaryObjectType):
datafiles: List[Annotated["DataFileType", strawberry.lazy('core.graphql.types')]] datafiles: List[Annotated["DataFileType", strawberry.lazy('core.graphql.types')]]

View File

@@ -0,0 +1,19 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0019_configrevision_active'),
('users', '0015_owner'),
]
operations = [
migrations.AddField(
model_name='datasource',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
]

View File

@@ -2,7 +2,7 @@ from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from core.models import * from core.models import *
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, PrimaryModelTable, columns
from .columns import BackendTypeColumn from .columns import BackendTypeColumn
from .template_code import DATA_SOURCE_SYNC_BUTTON from .template_code import DATA_SOURCE_SYNC_BUTTON
@@ -12,7 +12,7 @@ __all__ = (
) )
class DataSourceTable(NetBoxTable): class DataSourceTable(PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True, linkify=True,
@@ -42,7 +42,7 @@ class DataSourceTable(NetBoxTable):
extra_buttons=DATA_SOURCE_SYNC_BUTTON, extra_buttons=DATA_SOURCE_SYNC_BUTTON,
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = DataSource model = DataSource
fields = ( fields = (
'pk', 'id', 'name', 'type', 'status', 'enabled', 'source_url', 'description', 'sync_interval', 'comments', 'pk', 'id', 'name', 'type', 'status', 'enabled', 'source_url', 'description', 'sync_interval', 'comments',

View File

@@ -5,7 +5,9 @@ from rest_framework import serializers
from dcim.choices import * from dcim.choices import *
from dcim.models import Cable, CablePath, CableTermination from dcim.models import Cable, CablePath, CableTermination
from netbox.api.fields import ChoiceField, ContentTypeField from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.serializers import BaseModelSerializer, GenericObjectSerializer, NetBoxModelSerializer from netbox.api.serializers import (
BaseModelSerializer, GenericObjectSerializer, NetBoxModelSerializer, PrimaryModelSerializer,
)
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
@@ -18,7 +20,7 @@ __all__ = (
) )
class CableSerializer(NetBoxModelSerializer): class CableSerializer(PrimaryModelSerializer):
a_terminations = GenericObjectSerializer(many=True, required=False) a_terminations = GenericObjectSerializer(many=True, required=False)
b_terminations = GenericObjectSerializer(many=True, required=False) b_terminations = GenericObjectSerializer(many=True, required=False)
status = ChoiceField(choices=LinkStatusChoices, required=False) status = ChoiceField(choices=LinkStatusChoices, required=False)
@@ -29,8 +31,8 @@ class CableSerializer(NetBoxModelSerializer):
model = Cable model = Cable
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant', 'id', 'url', 'display_url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant',
'label', 'color', 'length', 'length_unit', 'description', 'comments', 'tags', 'custom_fields', 'created', 'label', 'color', 'length', 'length_unit', 'description', 'owner', 'comments', 'tags', 'custom_fields',
'last_updated', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'label', 'description') brief_fields = ('id', 'url', 'display', 'label', 'description')

View File

@@ -11,15 +11,15 @@ from dcim.models import Device, DeviceBay, MACAddress, Module, VirtualDeviceCont
from extras.api.serializers_.configtemplates import ConfigTemplateSerializer from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
from ipam.api.serializers_.ip import IPAddressSerializer from ipam.api.serializers_.ip import IPAddressSerializer
from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField from netbox.api.fields import ChoiceField, ContentTypeField, RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import PrimaryModelSerializer
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from virtualization.api.serializers_.clusters import ClusterSerializer from virtualization.api.serializers_.clusters import ClusterSerializer
from .devicetypes import * from .devicetypes import *
from .nested import NestedDeviceBaySerializer, NestedDeviceSerializer, NestedModuleBaySerializer
from .platforms import PlatformSerializer from .platforms import PlatformSerializer
from .racks import RackSerializer from .racks import RackSerializer
from .roles import DeviceRoleSerializer from .roles import DeviceRoleSerializer
from .nested import NestedDeviceBaySerializer, NestedDeviceSerializer, NestedModuleBaySerializer
from .sites import LocationSerializer, SiteSerializer from .sites import LocationSerializer, SiteSerializer
from .virtualchassis import VirtualChassisSerializer from .virtualchassis import VirtualChassisSerializer
@@ -32,7 +32,7 @@ __all__ = (
) )
class DeviceSerializer(NetBoxModelSerializer): class DeviceSerializer(PrimaryModelSerializer):
device_type = DeviceTypeSerializer(nested=True) device_type = DeviceTypeSerializer(nested=True)
role = DeviceRoleSerializer(nested=True) role = DeviceRoleSerializer(nested=True)
tenant = TenantSerializer( tenant = TenantSerializer(
@@ -84,8 +84,8 @@ class DeviceSerializer(NetBoxModelSerializer):
'id', 'url', 'display_url', 'display', 'name', 'device_type', 'role', 'tenant', 'platform', 'serial', 'id', 'url', 'display_url', 'display', 'name', 'device_type', 'role', 'tenant', 'platform', 'serial',
'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent_device', 'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent_device',
'status', 'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis', 'status', 'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis',
'vc_position', 'vc_priority', 'description', 'comments', 'config_template', 'local_context_data', 'tags', 'vc_position', 'vc_priority', 'description', 'owner', 'comments', 'config_template', 'local_context_data',
'custom_fields', 'created', 'last_updated', 'console_port_count', 'console_server_port_count', 'tags', 'custom_fields', 'created', 'last_updated', 'console_port_count', 'console_server_port_count',
'power_port_count', 'power_outlet_count', 'interface_count', 'front_port_count', 'rear_port_count', 'power_port_count', 'power_outlet_count', 'interface_count', 'front_port_count', 'rear_port_count',
'device_bay_count', 'module_bay_count', 'inventory_item_count', 'device_bay_count', 'module_bay_count', 'inventory_item_count',
] ]
@@ -122,7 +122,7 @@ class DeviceWithConfigContextSerializer(DeviceSerializer):
return obj.get_config_context() return obj.get_config_context()
class VirtualDeviceContextSerializer(NetBoxModelSerializer): class VirtualDeviceContextSerializer(PrimaryModelSerializer):
device = DeviceSerializer(nested=True) device = DeviceSerializer(nested=True)
identifier = serializers.IntegerField(allow_null=True, max_value=32767, min_value=0, required=False, default=None) identifier = serializers.IntegerField(allow_null=True, max_value=32767, min_value=0, required=False, default=None)
tenant = TenantSerializer(nested=True, required=False, allow_null=True, default=None) tenant = TenantSerializer(nested=True, required=False, allow_null=True, default=None)
@@ -138,13 +138,13 @@ class VirtualDeviceContextSerializer(NetBoxModelSerializer):
model = VirtualDeviceContext model = VirtualDeviceContext
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'device', 'identifier', 'tenant', 'primary_ip', 'id', 'url', 'display_url', 'display', 'name', 'device', 'identifier', 'tenant', 'primary_ip',
'primary_ip4', 'primary_ip6', 'status', 'description', 'comments', 'tags', 'custom_fields', 'primary_ip4', 'primary_ip6', 'status', 'description', 'owner', 'comments', 'tags', 'custom_fields',
'created', 'last_updated', 'interface_count', 'created', 'last_updated', 'interface_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'identifier', 'device', 'description') brief_fields = ('id', 'url', 'display', 'name', 'identifier', 'device', 'description')
class ModuleSerializer(NetBoxModelSerializer): class ModuleSerializer(PrimaryModelSerializer):
device = DeviceSerializer(nested=True) device = DeviceSerializer(nested=True)
module_bay = NestedModuleBaySerializer() module_bay = NestedModuleBaySerializer()
module_type = ModuleTypeSerializer(nested=True) module_type = ModuleTypeSerializer(nested=True)
@@ -154,12 +154,12 @@ class ModuleSerializer(NetBoxModelSerializer):
model = Module model = Module
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'device', 'module_bay', 'module_type', 'status', 'serial', 'id', 'url', 'display_url', 'display', 'device', 'module_bay', 'module_type', 'status', 'serial',
'asset_tag', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'asset_tag', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'device', 'module_bay', 'module_type', 'description') brief_fields = ('id', 'url', 'display', 'device', 'module_bay', 'module_type', 'description')
class MACAddressSerializer(NetBoxModelSerializer): class MACAddressSerializer(PrimaryModelSerializer):
assigned_object_type = ContentTypeField( assigned_object_type = ContentTypeField(
queryset=ContentType.objects.filter(MACADDRESS_ASSIGNMENT_MODELS), queryset=ContentType.objects.filter(MACADDRESS_ASSIGNMENT_MODELS),
required=False, required=False,
@@ -171,7 +171,7 @@ class MACAddressSerializer(NetBoxModelSerializer):
model = MACAddress model = MACAddress
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'mac_address', 'assigned_object_type', 'assigned_object_id', 'id', 'url', 'display_url', 'display', 'mac_address', 'assigned_object_type', 'assigned_object_id',
'assigned_object', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'assigned_object', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'mac_address', 'description') brief_fields = ('id', 'url', 'display', 'mac_address', 'description')

View File

@@ -6,7 +6,7 @@ from rest_framework import serializers
from dcim.choices import * from dcim.choices import *
from dcim.models import DeviceType, ModuleType, ModuleTypeProfile from dcim.models import DeviceType, ModuleType, ModuleTypeProfile
from netbox.api.fields import AttributesField, ChoiceField, RelatedObjectCountField from netbox.api.fields import AttributesField, ChoiceField, RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import PrimaryModelSerializer
from netbox.choices import * from netbox.choices import *
from .manufacturers import ManufacturerSerializer from .manufacturers import ManufacturerSerializer
from .platforms import PlatformSerializer from .platforms import PlatformSerializer
@@ -18,7 +18,7 @@ __all__ = (
) )
class DeviceTypeSerializer(NetBoxModelSerializer): class DeviceTypeSerializer(PrimaryModelSerializer):
manufacturer = ManufacturerSerializer(nested=True) manufacturer = ManufacturerSerializer(nested=True)
default_platform = PlatformSerializer(nested=True, required=False, allow_null=True) default_platform = PlatformSerializer(nested=True, required=False, allow_null=True)
u_height = serializers.DecimalField( u_height = serializers.DecimalField(
@@ -54,7 +54,7 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'id', 'url', 'display_url', 'display', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number',
'u_height', 'exclude_from_utilization', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'u_height', 'exclude_from_utilization', 'is_full_depth', 'subdevice_role', 'airflow', 'weight',
'weight_unit', 'front_image', 'rear_image', 'description', 'comments', 'tags', 'custom_fields', 'weight_unit', 'front_image', 'rear_image', 'description', 'owner', 'comments', 'tags', 'custom_fields',
'created', 'last_updated', 'device_count', 'console_port_template_count', 'created', 'last_updated', 'device_count', 'console_port_template_count',
'console_server_port_template_count', 'power_port_template_count', 'power_outlet_template_count', 'console_server_port_template_count', 'power_port_template_count', 'power_outlet_template_count',
'interface_template_count', 'front_port_template_count', 'rear_port_template_count', 'interface_template_count', 'front_port_template_count', 'rear_port_template_count',
@@ -63,18 +63,18 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description', 'device_count') brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description', 'device_count')
class ModuleTypeProfileSerializer(NetBoxModelSerializer): class ModuleTypeProfileSerializer(PrimaryModelSerializer):
class Meta: class Meta:
model = ModuleTypeProfile model = ModuleTypeProfile
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'schema', 'comments', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'description', 'schema', 'owner', 'comments', 'tags',
'created', 'last_updated', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')
class ModuleTypeSerializer(NetBoxModelSerializer): class ModuleTypeSerializer(PrimaryModelSerializer):
profile = ModuleTypeProfileSerializer( profile = ModuleTypeProfileSerializer(
nested=True, nested=True,
required=False, required=False,
@@ -105,7 +105,7 @@ class ModuleTypeSerializer(NetBoxModelSerializer):
model = ModuleType model = ModuleType
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'profile', 'manufacturer', 'model', 'part_number', 'airflow', 'id', 'url', 'display_url', 'display', 'profile', 'manufacturer', 'model', 'part_number', 'airflow',
'weight', 'weight_unit', 'description', 'attributes', 'comments', 'tags', 'custom_fields', 'created', 'weight', 'weight_unit', 'description', 'attributes', 'owner', 'comments', 'tags', 'custom_fields',
'last_updated', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'profile', 'manufacturer', 'model', 'description') brief_fields = ('id', 'url', 'display', 'profile', 'manufacturer', 'model', 'description')

View File

@@ -1,13 +1,13 @@
from dcim.models import Manufacturer from dcim.models import Manufacturer
from netbox.api.fields import RelatedObjectCountField from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import OrganizationalModelSerializer
__all__ = ( __all__ = (
'ManufacturerSerializer', 'ManufacturerSerializer',
) )
class ManufacturerSerializer(NetBoxModelSerializer): class ManufacturerSerializer(OrganizationalModelSerializer):
# Related object counts # Related object counts
devicetype_count = RelatedObjectCountField('device_types') devicetype_count = RelatedObjectCountField('device_types')
@@ -17,7 +17,7 @@ class ManufacturerSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = Manufacturer model = Manufacturer
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'description', 'owner', 'tags', 'custom_fields',
'created', 'last_updated', 'devicetype_count', 'inventoryitem_count', 'platform_count', 'created', 'last_updated', 'devicetype_count', 'inventoryitem_count', 'platform_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'devicetype_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'devicetype_count')

View File

@@ -24,7 +24,7 @@ class PlatformSerializer(NestedGroupModelSerializer):
model = Platform model = Platform
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'parent', 'name', 'slug', 'manufacturer', 'config_template', 'id', 'url', 'display_url', 'display', 'parent', 'name', 'slug', 'manufacturer', 'config_template',
'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
'virtualmachine_count', '_depth', 'virtualmachine_count', '_depth',
] ]
brief_fields = ( brief_fields = (

View File

@@ -1,7 +1,7 @@
from dcim.choices import * from dcim.choices import *
from dcim.models import PowerFeed, PowerPanel from dcim.models import PowerFeed, PowerPanel
from netbox.api.fields import ChoiceField, RelatedObjectCountField from netbox.api.fields import ChoiceField, RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import PrimaryModelSerializer
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
from .base import ConnectedEndpointsSerializer from .base import ConnectedEndpointsSerializer
from .cables import CabledObjectSerializer from .cables import CabledObjectSerializer
@@ -14,7 +14,7 @@ __all__ = (
) )
class PowerPanelSerializer(NetBoxModelSerializer): class PowerPanelSerializer(PrimaryModelSerializer):
site = SiteSerializer(nested=True) site = SiteSerializer(nested=True)
location = LocationSerializer( location = LocationSerializer(
nested=True, nested=True,
@@ -29,13 +29,13 @@ class PowerPanelSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = PowerPanel model = PowerPanel
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'site', 'location', 'name', 'description', 'comments', 'tags', 'id', 'url', 'display_url', 'display', 'site', 'location', 'name', 'description', 'owner', 'comments',
'custom_fields', 'powerfeed_count', 'created', 'last_updated', 'tags', 'custom_fields', 'powerfeed_count', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description', 'powerfeed_count') brief_fields = ('id', 'url', 'display', 'name', 'description', 'powerfeed_count')
class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer): class PowerFeedSerializer(PrimaryModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
power_panel = PowerPanelSerializer(nested=True) power_panel = PowerPanelSerializer(nested=True)
rack = RackSerializer( rack = RackSerializer(
nested=True, nested=True,
@@ -71,6 +71,7 @@ class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
'id', 'url', 'display_url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'id', 'url', 'display_url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply',
'phase', 'voltage', 'amperage', 'max_utilization', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'phase', 'voltage', 'amperage', 'max_utilization', 'mark_connected', 'cable', 'cable_end', 'link_peers',
'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable',
'description', 'tenant', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', 'description', 'tenant', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
'_occupied',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description', 'cable', '_occupied') brief_fields = ('id', 'url', 'display', 'name', 'description', 'cable', '_occupied')

View File

@@ -5,7 +5,7 @@ from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.models import Rack, RackReservation, RackRole, RackType from dcim.models import Rack, RackReservation, RackRole, RackType
from netbox.api.fields import ChoiceField, RelatedObjectCountField from netbox.api.fields import ChoiceField, RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import OrganizationalModelSerializer, PrimaryModelSerializer
from netbox.choices import * from netbox.choices import *
from netbox.config import ConfigItem from netbox.config import ConfigItem
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
@@ -22,7 +22,7 @@ __all__ = (
) )
class RackRoleSerializer(NetBoxModelSerializer): class RackRoleSerializer(OrganizationalModelSerializer):
# Related object counts # Related object counts
rack_count = RelatedObjectCountField('racks') rack_count = RelatedObjectCountField('racks')
@@ -30,13 +30,13 @@ class RackRoleSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = RackRole model = RackRole
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'owner', 'tags',
'created', 'last_updated', 'rack_count', 'custom_fields', 'created', 'last_updated', 'rack_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count')
class RackBaseSerializer(NetBoxModelSerializer): class RackBaseSerializer(PrimaryModelSerializer):
form_factor = ChoiceField( form_factor = ChoiceField(
choices=RackFormFactorChoices, choices=RackFormFactorChoices,
allow_blank=True, allow_blank=True,
@@ -71,8 +71,8 @@ class RackTypeSerializer(RackBaseSerializer):
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'manufacturer', 'model', 'slug', 'description', 'form_factor', 'id', 'url', 'display_url', 'display', 'manufacturer', 'model', 'slug', 'description', 'form_factor',
'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'outer_height', 'outer_depth',
'outer_unit', 'weight', 'max_weight', 'weight_unit', 'mounting_depth', 'description', 'comments', 'tags', 'outer_unit', 'weight', 'max_weight', 'weight_unit', 'mounting_depth', 'description', 'owner', 'comments',
'custom_fields', 'created', 'last_updated', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description') brief_fields = ('id', 'url', 'display', 'manufacturer', 'model', 'slug', 'description')
@@ -130,13 +130,13 @@ class RackSerializer(RackBaseSerializer):
'id', 'url', 'display_url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'id', 'url', 'display_url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status',
'role', 'serial', 'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'weight', 'role', 'serial', 'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'weight',
'max_weight', 'weight_unit', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'max_weight', 'weight_unit', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit',
'mounting_depth', 'airflow', 'description', 'comments', 'tags', 'custom_fields', 'mounting_depth', 'airflow', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created',
'created', 'last_updated', 'device_count', 'powerfeed_count', 'last_updated', 'device_count', 'powerfeed_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description', 'device_count') brief_fields = ('id', 'url', 'display', 'name', 'description', 'device_count')
class RackReservationSerializer(NetBoxModelSerializer): class RackReservationSerializer(PrimaryModelSerializer):
rack = RackSerializer( rack = RackSerializer(
nested=True, nested=True,
) )
@@ -157,7 +157,7 @@ class RackReservationSerializer(NetBoxModelSerializer):
model = RackReservation model = RackReservation
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'rack', 'units', 'status', 'created', 'last_updated', 'user', 'id', 'url', 'display_url', 'display', 'rack', 'units', 'status', 'created', 'last_updated', 'user',
'tenant', 'description', 'comments', 'tags', 'custom_fields', 'tenant', 'description', 'owner', 'comments', 'tags', 'custom_fields',
] ]
brief_fields = ('id', 'url', 'display', 'status', 'user', 'description', 'units') brief_fields = ('id', 'url', 'display', 'status', 'user', 'description', 'units')

View File

@@ -3,7 +3,7 @@ from rest_framework import serializers
from dcim.models import DeviceRole, InventoryItemRole from dcim.models import DeviceRole, InventoryItemRole
from extras.api.serializers_.configtemplates import ConfigTemplateSerializer from extras.api.serializers_.configtemplates import ConfigTemplateSerializer
from netbox.api.fields import RelatedObjectCountField from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer from netbox.api.serializers import NestedGroupModelSerializer, OrganizationalModelSerializer
from .nested import NestedDeviceRoleSerializer from .nested import NestedDeviceRoleSerializer
__all__ = ( __all__ = (
@@ -23,14 +23,14 @@ class DeviceRoleSerializer(NestedGroupModelSerializer):
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', 'parent', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', 'parent',
'description', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
'comments', '_depth', 'owner', 'comments', '_depth',
] ]
brief_fields = ( brief_fields = (
'id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count', '_depth' 'id', 'url', 'display', 'name', 'slug', 'description', 'device_count', 'virtualmachine_count', '_depth'
) )
class InventoryItemRoleSerializer(NetBoxModelSerializer): class InventoryItemRoleSerializer(OrganizationalModelSerializer):
# Related object counts # Related object counts
inventoryitem_count = RelatedObjectCountField('inventory_items') inventoryitem_count = RelatedObjectCountField('inventory_items')
@@ -38,7 +38,7 @@ class InventoryItemRoleSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = InventoryItemRole model = InventoryItemRole
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'color', 'description', 'owner', 'tags',
'created', 'last_updated', 'inventoryitem_count', 'custom_fields', 'created', 'last_updated', 'inventoryitem_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'inventoryitem_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'inventoryitem_count')

View File

@@ -6,7 +6,7 @@ from dcim.models import Location, Region, Site, SiteGroup
from ipam.api.serializers_.asns import ASNSerializer from ipam.api.serializers_.asns import ASNSerializer
from ipam.models import ASN from ipam.models import ASN
from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField from netbox.api.fields import ChoiceField, RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import NestedGroupModelSerializer, NetBoxModelSerializer from netbox.api.serializers import NestedGroupModelSerializer, PrimaryModelSerializer
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
from .nested import NestedLocationSerializer, NestedRegionSerializer, NestedSiteGroupSerializer from .nested import NestedLocationSerializer, NestedRegionSerializer, NestedSiteGroupSerializer
@@ -27,7 +27,7 @@ class RegionSerializer(NestedGroupModelSerializer):
model = Region model = Region
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
'created', 'last_updated', 'site_count', 'prefix_count', 'comments', '_depth', 'created', 'last_updated', 'site_count', 'prefix_count', 'owner', 'comments', '_depth',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth')
@@ -41,12 +41,12 @@ class SiteGroupSerializer(NestedGroupModelSerializer):
model = SiteGroup model = SiteGroup
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields',
'created', 'last_updated', 'site_count', 'prefix_count', 'comments', '_depth', 'created', 'last_updated', 'site_count', 'prefix_count', 'owner', 'comments', '_depth',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'site_count', '_depth')
class SiteSerializer(NetBoxModelSerializer): class SiteSerializer(PrimaryModelSerializer):
status = ChoiceField(choices=SiteStatusChoices, required=False) status = ChoiceField(choices=SiteStatusChoices, required=False)
region = RegionSerializer(nested=True, required=False, allow_null=True) region = RegionSerializer(nested=True, required=False, allow_null=True)
group = SiteGroupSerializer(nested=True, required=False, allow_null=True) group = SiteGroupSerializer(nested=True, required=False, allow_null=True)
@@ -72,7 +72,7 @@ class SiteSerializer(NetBoxModelSerializer):
model = Site model = Site
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility',
'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'time_zone', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'owner',
'comments', 'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count', 'device_count', 'comments', 'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count', 'device_count',
'prefix_count', 'rack_count', 'virtualmachine_count', 'vlan_count', 'prefix_count', 'rack_count', 'virtualmachine_count', 'vlan_count',
] ]
@@ -93,6 +93,6 @@ class LocationSerializer(NestedGroupModelSerializer):
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'facility', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'facility',
'description', 'tags', 'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count',
'prefix_count', 'comments', '_depth', 'prefix_count', 'owner', 'comments', '_depth',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count', '_depth') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'rack_count', '_depth')

View File

@@ -1,7 +1,7 @@
from rest_framework import serializers from rest_framework import serializers
from dcim.models import VirtualChassis from dcim.models import VirtualChassis
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import PrimaryModelSerializer
from .nested import NestedDeviceSerializer from .nested import NestedDeviceSerializer
__all__ = ( __all__ = (
@@ -9,7 +9,7 @@ __all__ = (
) )
class VirtualChassisSerializer(NetBoxModelSerializer): class VirtualChassisSerializer(PrimaryModelSerializer):
master = NestedDeviceSerializer(required=False, allow_null=True, default=None) master = NestedDeviceSerializer(required=False, allow_null=True, default=None)
members = NestedDeviceSerializer(many=True, read_only=True) members = NestedDeviceSerializer(many=True, read_only=True)
@@ -19,7 +19,7 @@ class VirtualChassisSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = VirtualChassis model = VirtualChassis
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags', 'id', 'url', 'display_url', 'display', 'name', 'domain', 'master', 'description', 'owner', 'comments',
'custom_fields', 'created', 'last_updated', 'member_count', 'members', 'tags', 'custom_fields', 'created', 'last_updated', 'member_count', 'members',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'master', 'description', 'member_count') brief_fields = ('id', 'url', 'display', 'name', 'master', 'description', 'member_count')

View File

@@ -11,11 +11,12 @@ from ipam.filtersets import PrimaryIPFilterSet
from ipam.models import ASN, IPAddress, VLANTranslationPolicy, VRF from ipam.models import ASN, IPAddress, VLANTranslationPolicy, VRF
from netbox.choices import ColorChoices from netbox.choices import ColorChoices
from netbox.filtersets import ( from netbox.filtersets import (
AttributeFiltersMixin, BaseFilterSet, ChangeLoggedModelFilterSet, NestedGroupModelFilterSet, NetBoxModelFilterSet, AttributeFiltersMixin, BaseFilterSet, ChangeLoggedModelFilterSet, NestedGroupModelFilterSet,
OrganizationalModelFilterSet, OrganizationalModelFilterSet, PrimaryModelFilterSet, NetBoxModelFilterSet,
) )
from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet from tenancy.filtersets import TenancyFilterSet, ContactModelFilterSet
from tenancy.models import * from tenancy.models import *
from users.filterset_mixins import OwnerFilterMixin
from users.models import User from users.models import User
from utilities.filters import ( from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueWWNFilter, ContentTypeFilter, MultiValueCharFilter, MultiValueMACAddressFilter, MultiValueNumberFilter, MultiValueWWNFilter,
@@ -143,7 +144,7 @@ class SiteGroupFilterSet(NestedGroupModelFilterSet, ContactModelFilterSet):
fields = ('id', 'name', 'slug', 'description') fields = ('id', 'name', 'slug', 'description')
class SiteFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet): class SiteFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
status = django_filters.MultipleChoiceFilter( status = django_filters.MultipleChoiceFilter(
choices=SiteStatusChoices, choices=SiteStatusChoices,
null_value=None null_value=None
@@ -293,7 +294,7 @@ class RackRoleFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'color', 'description') fields = ('id', 'name', 'slug', 'color', 'description')
class RackTypeFilterSet(NetBoxModelFilterSet): class RackTypeFilterSet(PrimaryModelFilterSet):
manufacturer_id = django_filters.ModelMultipleChoiceFilter( manufacturer_id = django_filters.ModelMultipleChoiceFilter(
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
label=_('Manufacturer (ID)'), label=_('Manufacturer (ID)'),
@@ -328,7 +329,7 @@ class RackTypeFilterSet(NetBoxModelFilterSet):
) )
class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet): class RackFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
region_id = TreeNodeMultipleChoiceFilter( region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
@@ -444,7 +445,7 @@ class RackFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSe
) )
class RackReservationFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class RackReservationFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
rack_id = django_filters.ModelMultipleChoiceFilter( rack_id = django_filters.ModelMultipleChoiceFilter(
queryset=Rack.objects.all(), queryset=Rack.objects.all(),
label=_('Rack (ID)'), label=_('Rack (ID)'),
@@ -540,7 +541,7 @@ class ManufacturerFilterSet(OrganizationalModelFilterSet, ContactModelFilterSet)
fields = ('id', 'name', 'slug', 'description') fields = ('id', 'name', 'slug', 'description')
class DeviceTypeFilterSet(NetBoxModelFilterSet): class DeviceTypeFilterSet(PrimaryModelFilterSet):
manufacturer_id = django_filters.ModelMultipleChoiceFilter( manufacturer_id = django_filters.ModelMultipleChoiceFilter(
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
label=_('Manufacturer (ID)'), label=_('Manufacturer (ID)'),
@@ -682,7 +683,7 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet):
return queryset.exclude(inventoryitemtemplates__isnull=value) return queryset.exclude(inventoryitemtemplates__isnull=value)
class ModuleTypeProfileFilterSet(NetBoxModelFilterSet): class ModuleTypeProfileFilterSet(PrimaryModelFilterSet):
class Meta: class Meta:
model = ModuleTypeProfile model = ModuleTypeProfile
@@ -698,7 +699,7 @@ class ModuleTypeProfileFilterSet(NetBoxModelFilterSet):
) )
class ModuleTypeFilterSet(AttributeFiltersMixin, NetBoxModelFilterSet): class ModuleTypeFilterSet(AttributeFiltersMixin, PrimaryModelFilterSet):
profile_id = django_filters.ModelMultipleChoiceFilter( profile_id = django_filters.ModelMultipleChoiceFilter(
queryset=ModuleTypeProfile.objects.all(), queryset=ModuleTypeProfile.objects.all(),
label=_('Profile (ID)'), label=_('Profile (ID)'),
@@ -951,7 +952,7 @@ class InventoryItemTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeCompo
return queryset.filter(qs_filter) return queryset.filter(qs_filter)
class DeviceRoleFilterSet(OrganizationalModelFilterSet): class DeviceRoleFilterSet(NestedGroupModelFilterSet):
config_template_id = django_filters.ModelMultipleChoiceFilter( config_template_id = django_filters.ModelMultipleChoiceFilter(
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
label=_('Config template (ID)'), label=_('Config template (ID)'),
@@ -985,7 +986,7 @@ class DeviceRoleFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'color', 'vm_role', 'description') fields = ('id', 'name', 'slug', 'color', 'vm_role', 'description')
class PlatformFilterSet(OrganizationalModelFilterSet): class PlatformFilterSet(NestedGroupModelFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
label=_('Immediate parent platform (ID)'), label=_('Immediate parent platform (ID)'),
@@ -1043,7 +1044,7 @@ class PlatformFilterSet(OrganizationalModelFilterSet):
class DeviceFilterSet( class DeviceFilterSet(
NetBoxModelFilterSet, PrimaryModelFilterSet,
TenancyFilterSet, TenancyFilterSet,
ContactModelFilterSet, ContactModelFilterSet,
LocalConfigContextFilterSet, LocalConfigContextFilterSet,
@@ -1345,7 +1346,7 @@ class DeviceFilterSet(
return queryset.exclude(params) return queryset.exclude(params)
class VirtualDeviceContextFilterSet(NetBoxModelFilterSet, TenancyFilterSet, PrimaryIPFilterSet): class VirtualDeviceContextFilterSet(PrimaryModelFilterSet, TenancyFilterSet, PrimaryIPFilterSet):
device_id = django_filters.ModelMultipleChoiceFilter( device_id = django_filters.ModelMultipleChoiceFilter(
field_name='device', field_name='device',
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1394,7 +1395,7 @@ class VirtualDeviceContextFilterSet(NetBoxModelFilterSet, TenancyFilterSet, Prim
return queryset.exclude(params) return queryset.exclude(params)
class ModuleFilterSet(NetBoxModelFilterSet): class ModuleFilterSet(PrimaryModelFilterSet):
manufacturer_id = django_filters.ModelMultipleChoiceFilter( manufacturer_id = django_filters.ModelMultipleChoiceFilter(
field_name='module_type__manufacturer', field_name='module_type__manufacturer',
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@@ -1516,7 +1517,7 @@ class ModuleFilterSet(NetBoxModelFilterSet):
).distinct() ).distinct()
class DeviceComponentFilterSet(django_filters.FilterSet): class DeviceComponentFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -1682,12 +1683,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( class ConsolePortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, PathEndpointFilterSet):
ModularDeviceComponentFilterSet,
NetBoxModelFilterSet,
CabledObjectFilterSet,
PathEndpointFilterSet
):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=ConsolePortTypeChoices, choices=ConsolePortTypeChoices,
null_value=None null_value=None
@@ -1698,12 +1694,7 @@ class ConsolePortFilterSet(
fields = ('id', 'name', 'label', 'speed', 'description', 'mark_connected', 'cable_end') fields = ('id', 'name', 'label', 'speed', 'description', 'mark_connected', 'cable_end')
class ConsoleServerPortFilterSet( class ConsoleServerPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, PathEndpointFilterSet):
ModularDeviceComponentFilterSet,
NetBoxModelFilterSet,
CabledObjectFilterSet,
PathEndpointFilterSet
):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=ConsolePortTypeChoices, choices=ConsolePortTypeChoices,
null_value=None null_value=None
@@ -1714,12 +1705,7 @@ class ConsoleServerPortFilterSet(
fields = ('id', 'name', 'label', 'speed', 'description', 'mark_connected', 'cable_end') fields = ('id', 'name', 'label', 'speed', 'description', 'mark_connected', 'cable_end')
class PowerPortFilterSet( class PowerPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, PathEndpointFilterSet):
ModularDeviceComponentFilterSet,
NetBoxModelFilterSet,
CabledObjectFilterSet,
PathEndpointFilterSet
):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PowerPortTypeChoices, choices=PowerPortTypeChoices,
null_value=None null_value=None
@@ -1732,12 +1718,7 @@ class PowerPortFilterSet(
) )
class PowerOutletFilterSet( class PowerOutletFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet, PathEndpointFilterSet):
ModularDeviceComponentFilterSet,
NetBoxModelFilterSet,
CabledObjectFilterSet,
PathEndpointFilterSet
):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PowerOutletTypeChoices, choices=PowerOutletTypeChoices,
null_value=None null_value=None
@@ -1762,7 +1743,7 @@ class PowerOutletFilterSet(
) )
class MACAddressFilterSet(NetBoxModelFilterSet): class MACAddressFilterSet(PrimaryModelFilterSet):
mac_address = MultiValueMACAddressFilter() mac_address = MultiValueMACAddressFilter()
assigned_object_type = ContentTypeFilter() assigned_object_type = ContentTypeFilter()
device = MultiValueCharFilter( device = MultiValueCharFilter(
@@ -1914,7 +1895,6 @@ class CommonInterfaceFilterSet(django_filters.FilterSet):
class InterfaceFilterSet( class InterfaceFilterSet(
ModularDeviceComponentFilterSet, ModularDeviceComponentFilterSet,
NetBoxModelFilterSet,
CabledObjectFilterSet, CabledObjectFilterSet,
PathEndpointFilterSet, PathEndpointFilterSet,
CommonInterfaceFilterSet CommonInterfaceFilterSet
@@ -2075,11 +2055,7 @@ class InterfaceFilterSet(
) )
class FrontPortFilterSet( class FrontPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet):
ModularDeviceComponentFilterSet,
NetBoxModelFilterSet,
CabledObjectFilterSet
):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PortTypeChoices, choices=PortTypeChoices,
null_value=None null_value=None
@@ -2095,11 +2071,7 @@ class FrontPortFilterSet(
) )
class RearPortFilterSet( class RearPortFilterSet(ModularDeviceComponentFilterSet, CabledObjectFilterSet):
ModularDeviceComponentFilterSet,
NetBoxModelFilterSet,
CabledObjectFilterSet
):
type = django_filters.MultipleChoiceFilter( type = django_filters.MultipleChoiceFilter(
choices=PortTypeChoices, choices=PortTypeChoices,
null_value=None null_value=None
@@ -2112,7 +2084,7 @@ class RearPortFilterSet(
) )
class ModuleBayFilterSet(ModularDeviceComponentFilterSet, NetBoxModelFilterSet): class ModuleBayFilterSet(ModularDeviceComponentFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=ModuleBay.objects.all(), queryset=ModuleBay.objects.all(),
label=_('Parent module bay (ID)'), label=_('Parent module bay (ID)'),
@@ -2128,7 +2100,7 @@ class ModuleBayFilterSet(ModularDeviceComponentFilterSet, NetBoxModelFilterSet):
fields = ('id', 'name', 'label', 'position', 'description') fields = ('id', 'name', 'label', 'position', 'description')
class DeviceBayFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet): class DeviceBayFilterSet(DeviceComponentFilterSet):
installed_device_id = django_filters.ModelMultipleChoiceFilter( installed_device_id = django_filters.ModelMultipleChoiceFilter(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label=_('Installed device (ID)'), label=_('Installed device (ID)'),
@@ -2145,7 +2117,7 @@ class DeviceBayFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet):
fields = ('id', 'name', 'label', 'description') fields = ('id', 'name', 'label', 'description')
class InventoryItemFilterSet(DeviceComponentFilterSet, NetBoxModelFilterSet): class InventoryItemFilterSet(DeviceComponentFilterSet):
parent_id = django_filters.ModelMultipleChoiceFilter( parent_id = django_filters.ModelMultipleChoiceFilter(
queryset=InventoryItem.objects.all(), queryset=InventoryItem.objects.all(),
label=_('Parent inventory item (ID)'), label=_('Parent inventory item (ID)'),
@@ -2204,7 +2176,7 @@ class InventoryItemRoleFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'color', 'description') fields = ('id', 'name', 'slug', 'color', 'description')
class VirtualChassisFilterSet(NetBoxModelFilterSet): class VirtualChassisFilterSet(PrimaryModelFilterSet):
master_id = django_filters.ModelMultipleChoiceFilter( master_id = django_filters.ModelMultipleChoiceFilter(
queryset=Device.objects.all(), queryset=Device.objects.all(),
label=_('Master (ID)'), label=_('Master (ID)'),
@@ -2280,7 +2252,7 @@ class VirtualChassisFilterSet(NetBoxModelFilterSet):
return queryset.filter(qs_filter).distinct() return queryset.filter(qs_filter).distinct()
class CableFilterSet(TenancyFilterSet, NetBoxModelFilterSet): class CableFilterSet(TenancyFilterSet, PrimaryModelFilterSet):
termination_a_type = ContentTypeFilter( termination_a_type = ContentTypeFilter(
field_name='terminations__termination_type' field_name='terminations__termination_type'
) )
@@ -2457,7 +2429,7 @@ class CableTerminationFilterSet(ChangeLoggedModelFilterSet):
fields = ('id', 'cable', 'cable_end', 'termination_type', 'termination_id') fields = ('id', 'cable', 'cable_end', 'termination_type', 'termination_id')
class PowerPanelFilterSet(NetBoxModelFilterSet, ContactModelFilterSet): class PowerPanelFilterSet(PrimaryModelFilterSet, ContactModelFilterSet):
region_id = TreeNodeMultipleChoiceFilter( region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
@@ -2515,7 +2487,7 @@ class PowerPanelFilterSet(NetBoxModelFilterSet, ContactModelFilterSet):
return queryset.filter(qs_filter) return queryset.filter(qs_filter)
class PowerFeedFilterSet(NetBoxModelFilterSet, CabledObjectFilterSet, PathEndpointFilterSet, TenancyFilterSet): class PowerFeedFilterSet(PrimaryModelFilterSet, CabledObjectFilterSet, PathEndpointFilterSet, TenancyFilterSet):
region_id = TreeNodeMultipleChoiceFilter( region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='power_panel__site__region', field_name='power_panel__site__region',

View File

@@ -10,14 +10,14 @@ from extras.models import ConfigTemplate
from ipam.choices import VLANQinQRoleChoices from ipam.choices import VLANQinQRoleChoices
from ipam.models import ASN, VLAN, VLANGroup, VRF from ipam.models import ASN, VLAN, VLANGroup, VRF
from netbox.choices import * from netbox.choices import *
from netbox.forms import NetBoxModelBulkEditForm from netbox.forms import (
from netbox.forms.mixins import ChangelogMessageMixin NestedGroupModelBulkEditForm, NetBoxModelBulkEditForm, OrganizationalModelBulkEditForm, PrimaryModelBulkEditForm,
)
from netbox.forms.mixins import ChangelogMessageMixin, OwnerMixin
from tenancy.models import Tenant from tenancy.models import Tenant
from users.models import User from users.models import User
from utilities.forms import BulkEditForm, add_blank_choice, form_from_model from utilities.forms import BulkEditForm, add_blank_choice, form_from_model
from utilities.forms.fields import ( from utilities.forms.fields import ColorField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField
ColorField, CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField,
)
from utilities.forms.rendering import FieldSet, InlineFields, TabbedGroups from utilities.forms.rendering import FieldSet, InlineFields, TabbedGroups
from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions from utilities.forms.widgets import BulkEditNullBooleanSelect, NumberWithOptions
from virtualization.models import Cluster from virtualization.models import Cluster
@@ -71,18 +71,12 @@ __all__ = (
) )
class RegionBulkEditForm(NetBoxModelBulkEditForm): class RegionBulkEditForm(NestedGroupModelBulkEditForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=Region.objects.all(), queryset=Region.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Region model = Region
fieldsets = ( fieldsets = (
@@ -91,18 +85,12 @@ class RegionBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('parent', 'description', 'comments') nullable_fields = ('parent', 'description', 'comments')
class SiteGroupBulkEditForm(NetBoxModelBulkEditForm): class SiteGroupBulkEditForm(NestedGroupModelBulkEditForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = SiteGroup model = SiteGroup
fieldsets = ( fieldsets = (
@@ -111,7 +99,7 @@ class SiteGroupBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('parent', 'description', 'comments') nullable_fields = ('parent', 'description', 'comments')
class SiteBulkEditForm(NetBoxModelBulkEditForm): class SiteBulkEditForm(PrimaryModelBulkEditForm):
status = forms.ChoiceField( status = forms.ChoiceField(
label=_('Status'), label=_('Status'),
choices=add_blank_choice(SiteStatusChoices), choices=add_blank_choice(SiteStatusChoices),
@@ -162,12 +150,6 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm):
choices=add_blank_choice(TimeZoneFormField().choices), choices=add_blank_choice(TimeZoneFormField().choices),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Site model = Site
fieldsets = ( fieldsets = (
@@ -178,7 +160,7 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm):
) )
class LocationBulkEditForm(NetBoxModelBulkEditForm): class LocationBulkEditForm(NestedGroupModelBulkEditForm):
site = DynamicModelChoiceField( site = DynamicModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -208,12 +190,6 @@ class LocationBulkEditForm(NetBoxModelBulkEditForm):
max_length=50, max_length=50,
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Location model = Location
fieldsets = ( fieldsets = (
@@ -222,16 +198,11 @@ class LocationBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('parent', 'tenant', 'facility', 'description', 'comments') nullable_fields = ('parent', 'tenant', 'facility', 'description', 'comments')
class RackRoleBulkEditForm(NetBoxModelBulkEditForm): class RackRoleBulkEditForm(OrganizationalModelBulkEditForm):
color = ColorField( color = ColorField(
label=_('Color'), label=_('Color'),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = RackRole model = RackRole
fieldsets = ( fieldsets = (
@@ -240,7 +211,7 @@ class RackRoleBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('color', 'description') nullable_fields = ('color', 'description')
class RackTypeBulkEditForm(NetBoxModelBulkEditForm): class RackTypeBulkEditForm(PrimaryModelBulkEditForm):
manufacturer = DynamicModelChoiceField( manufacturer = DynamicModelChoiceField(
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@@ -310,12 +281,6 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
initial='' initial=''
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = RackType model = RackType
fieldsets = ( fieldsets = (
@@ -334,7 +299,7 @@ class RackTypeBulkEditForm(NetBoxModelBulkEditForm):
) )
class RackBulkEditForm(NetBoxModelBulkEditForm): class RackBulkEditForm(PrimaryModelBulkEditForm):
region = DynamicModelChoiceField( region = DynamicModelChoiceField(
label=_('Region'), label=_('Region'),
queryset=Region.objects.all(), queryset=Region.objects.all(),
@@ -464,12 +429,6 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
initial='' initial=''
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Rack model = Rack
fieldsets = ( fieldsets = (
@@ -485,7 +444,7 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
) )
class RackReservationBulkEditForm(NetBoxModelBulkEditForm): class RackReservationBulkEditForm(PrimaryModelBulkEditForm):
status = forms.ChoiceField( status = forms.ChoiceField(
label=_('Status'), label=_('Status'),
choices=add_blank_choice(RackReservationStatusChoices), choices=add_blank_choice(RackReservationStatusChoices),
@@ -502,12 +461,6 @@ class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = RackReservation model = RackReservation
fieldsets = ( fieldsets = (
@@ -516,13 +469,7 @@ class RackReservationBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('comments',) nullable_fields = ('comments',)
class ManufacturerBulkEditForm(NetBoxModelBulkEditForm): class ManufacturerBulkEditForm(OrganizationalModelBulkEditForm):
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = Manufacturer model = Manufacturer
fieldsets = ( fieldsets = (
FieldSet('description'), FieldSet('description'),
@@ -530,7 +477,7 @@ class ManufacturerBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('description',) nullable_fields = ('description',)
class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm): class DeviceTypeBulkEditForm(PrimaryModelBulkEditForm):
manufacturer = DynamicModelChoiceField( manufacturer = DynamicModelChoiceField(
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@@ -576,12 +523,6 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
initial='' initial=''
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = DeviceType model = DeviceType
fieldsets = ( fieldsets = (
@@ -594,17 +535,11 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments') nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments')
class ModuleTypeProfileBulkEditForm(NetBoxModelBulkEditForm): class ModuleTypeProfileBulkEditForm(PrimaryModelBulkEditForm):
schema = JSONField( schema = JSONField(
label=_('Schema'), label=_('Schema'),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = ModuleTypeProfile model = ModuleTypeProfile
fieldsets = ( fieldsets = (
@@ -613,7 +548,7 @@ class ModuleTypeProfileBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('description', 'comments') nullable_fields = ('description', 'comments')
class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm): class ModuleTypeBulkEditForm(PrimaryModelBulkEditForm):
profile = DynamicModelChoiceField( profile = DynamicModelChoiceField(
label=_('Profile'), label=_('Profile'),
queryset=ModuleTypeProfile.objects.all(), queryset=ModuleTypeProfile.objects.all(),
@@ -644,12 +579,6 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
initial='' initial=''
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = ModuleType model = ModuleType
fieldsets = ( fieldsets = (
@@ -663,7 +592,7 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('part_number', 'weight', 'weight_unit', 'profile', 'description', 'comments') nullable_fields = ('part_number', 'weight', 'weight_unit', 'profile', 'description', 'comments')
class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): class DeviceRoleBulkEditForm(NestedGroupModelBulkEditForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
@@ -683,12 +612,6 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = DeviceRole model = DeviceRole
fieldsets = ( fieldsets = (
@@ -697,7 +620,7 @@ class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('parent', 'color', 'config_template', 'description', 'comments') nullable_fields = ('parent', 'color', 'config_template', 'description', 'comments')
class PlatformBulkEditForm(NetBoxModelBulkEditForm): class PlatformBulkEditForm(NestedGroupModelBulkEditForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
@@ -713,12 +636,6 @@ class PlatformBulkEditForm(NetBoxModelBulkEditForm):
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Platform model = Platform
fieldsets = ( fieldsets = (
@@ -727,7 +644,7 @@ class PlatformBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('parent', 'manufacturer', 'config_template', 'description', 'comments') nullable_fields = ('parent', 'manufacturer', 'config_template', 'description', 'comments')
class DeviceBulkEditForm(NetBoxModelBulkEditForm): class DeviceBulkEditForm(PrimaryModelBulkEditForm):
manufacturer = DynamicModelChoiceField( manufacturer = DynamicModelChoiceField(
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@@ -787,11 +704,6 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
label=_('Serial Number') label=_('Serial Number')
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
config_template = DynamicModelChoiceField( config_template = DynamicModelChoiceField(
label=_('Config template'), label=_('Config template'),
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
@@ -805,7 +717,6 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm):
'site_id': ['$site', 'null'] 'site_id': ['$site', 'null']
}, },
) )
comments = CommentField()
model = Device model = Device
fieldsets = ( fieldsets = (
@@ -820,7 +731,7 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm):
) )
class ModuleBulkEditForm(NetBoxModelBulkEditForm): class ModuleBulkEditForm(PrimaryModelBulkEditForm):
manufacturer = DynamicModelChoiceField( manufacturer = DynamicModelChoiceField(
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@@ -848,12 +759,6 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
label=_('Serial Number') label=_('Serial Number')
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Module model = Module
fieldsets = ( fieldsets = (
@@ -862,7 +767,7 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('serial', 'description', 'comments') nullable_fields = ('serial', 'description', 'comments')
class CableBulkEditForm(NetBoxModelBulkEditForm): class CableBulkEditForm(PrimaryModelBulkEditForm):
type = forms.ChoiceField( type = forms.ChoiceField(
label=_('Type'), label=_('Type'),
choices=add_blank_choice(CableTypeChoices), choices=add_blank_choice(CableTypeChoices),
@@ -900,12 +805,6 @@ class CableBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
initial='' initial=''
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Cable model = Cable
fieldsets = ( fieldsets = (
@@ -917,18 +816,12 @@ class CableBulkEditForm(NetBoxModelBulkEditForm):
) )
class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm): class VirtualChassisBulkEditForm(PrimaryModelBulkEditForm):
domain = forms.CharField( domain = forms.CharField(
label=_('Domain'), label=_('Domain'),
max_length=30, max_length=30,
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = VirtualChassis model = VirtualChassis
fieldsets = ( fieldsets = (
@@ -937,7 +830,7 @@ class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('domain', 'description', 'comments') nullable_fields = ('domain', 'description', 'comments')
class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): class PowerPanelBulkEditForm(PrimaryModelBulkEditForm):
region = DynamicModelChoiceField( region = DynamicModelChoiceField(
label=_('Region'), label=_('Region'),
queryset=Region.objects.all(), queryset=Region.objects.all(),
@@ -971,12 +864,6 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
'site_id': '$site' 'site_id': '$site'
} }
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = PowerPanel model = PowerPanel
fieldsets = ( fieldsets = (
@@ -985,7 +872,7 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('location', 'description', 'comments') nullable_fields = ('location', 'description', 'comments')
class PowerFeedBulkEditForm(NetBoxModelBulkEditForm): class PowerFeedBulkEditForm(PrimaryModelBulkEditForm):
power_panel = DynamicModelChoiceField( power_panel = DynamicModelChoiceField(
label=_('Power panel'), label=_('Power panel'),
queryset=PowerPanel.objects.all(), queryset=PowerPanel.objects.all(),
@@ -1041,12 +928,6 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = PowerFeed model = PowerFeed
fieldsets = ( fieldsets = (
@@ -1369,7 +1250,7 @@ class InventoryItemTemplateBulkEditForm(ComponentTemplateBulkEditForm):
# Device components # Device components
# #
class ComponentBulkEditForm(NetBoxModelBulkEditForm): class ComponentBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
device = forms.ModelChoiceField( device = forms.ModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1822,16 +1703,11 @@ class InventoryItemBulkEditForm(
# Device component roles # Device component roles
# #
class InventoryItemRoleBulkEditForm(NetBoxModelBulkEditForm): class InventoryItemRoleBulkEditForm(OrganizationalModelBulkEditForm):
color = ColorField( color = ColorField(
label=_('Color'), label=_('Color'),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = InventoryItemRole model = InventoryItemRole
fieldsets = ( fieldsets = (
@@ -1840,7 +1716,7 @@ class InventoryItemRoleBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('color', 'description') nullable_fields = ('color', 'description')
class VirtualDeviceContextBulkEditForm(NetBoxModelBulkEditForm): class VirtualDeviceContextBulkEditForm(PrimaryModelBulkEditForm):
device = DynamicModelChoiceField( device = DynamicModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1856,6 +1732,7 @@ class VirtualDeviceContextBulkEditForm(NetBoxModelBulkEditForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False
) )
model = VirtualDeviceContext model = VirtualDeviceContext
fieldsets = ( fieldsets = (
FieldSet('device', 'status', 'tenant'), FieldSet('device', 'status', 'tenant'),
@@ -1867,14 +1744,7 @@ class VirtualDeviceContextBulkEditForm(NetBoxModelBulkEditForm):
# Addressing # Addressing
# #
class MACAddressBulkEditForm(NetBoxModelBulkEditForm): class MACAddressBulkEditForm(PrimaryModelBulkEditForm):
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = MACAddress model = MACAddress
fieldsets = ( fieldsets = (
FieldSet('description'), FieldSet('description'),

View File

@@ -11,7 +11,10 @@ from dcim.models import *
from extras.models import ConfigTemplate from extras.models import ConfigTemplate
from ipam.models import VRF, IPAddress from ipam.models import VRF, IPAddress
from netbox.choices import * from netbox.choices import *
from netbox.forms import NetBoxModelImportForm from netbox.forms import (
NestedGroupModelImportForm, NetBoxModelImportForm, OrganizationalModelImportForm, OwnerCSVMixin,
PrimaryModelImportForm,
)
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms.fields import ( from utilities.forms.fields import (
CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelMultipleChoiceField, CSVTypedChoiceField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelMultipleChoiceField, CSVTypedChoiceField,
@@ -58,7 +61,7 @@ __all__ = (
) )
class RegionImportForm(NetBoxModelImportForm): class RegionImportForm(NestedGroupModelImportForm):
parent = CSVModelChoiceField( parent = CSVModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=Region.objects.all(), queryset=Region.objects.all(),
@@ -69,10 +72,10 @@ class RegionImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = Region model = Region
fields = ('name', 'slug', 'parent', 'description', 'tags', 'comments') fields = ('name', 'slug', 'parent', 'description', 'owner', 'comments', 'tags')
class SiteGroupImportForm(NetBoxModelImportForm): class SiteGroupImportForm(NestedGroupModelImportForm):
parent = CSVModelChoiceField( parent = CSVModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
@@ -83,10 +86,10 @@ class SiteGroupImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = SiteGroup model = SiteGroup
fields = ('name', 'slug', 'parent', 'description', 'comments', 'tags') fields = ('name', 'slug', 'parent', 'description', 'owner', 'comments', 'tags')
class SiteImportForm(NetBoxModelImportForm): class SiteImportForm(PrimaryModelImportForm):
status = CSVChoiceField( status = CSVChoiceField(
label=_('Status'), label=_('Status'),
choices=SiteStatusChoices, choices=SiteStatusChoices,
@@ -118,7 +121,7 @@ class SiteImportForm(NetBoxModelImportForm):
model = Site model = Site
fields = ( fields = (
'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility', 'time_zone', 'description', 'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility', 'time_zone', 'description',
'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'tags' 'physical_address', 'shipping_address', 'latitude', 'longitude', 'owner', 'comments', 'tags'
) )
help_texts = { help_texts = {
'time_zone': mark_safe( 'time_zone': mark_safe(
@@ -129,7 +132,7 @@ class SiteImportForm(NetBoxModelImportForm):
} }
class LocationImportForm(NetBoxModelImportForm): class LocationImportForm(NestedGroupModelImportForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -162,8 +165,8 @@ class LocationImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = Location model = Location
fields = ( fields = (
'site', 'parent', 'name', 'slug', 'status', 'tenant', 'facility', 'description', 'site', 'parent', 'name', 'slug', 'status', 'tenant', 'facility', 'description', 'owner', 'comments',
'tags', 'comments', 'tags',
) )
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
@@ -175,15 +178,14 @@ class LocationImportForm(NetBoxModelImportForm):
self.fields['parent'].queryset = self.fields['parent'].queryset.filter(**params) self.fields['parent'].queryset = self.fields['parent'].queryset.filter(**params)
class RackRoleImportForm(NetBoxModelImportForm): class RackRoleImportForm(OrganizationalModelImportForm):
slug = SlugField()
class Meta: class Meta:
model = RackRole model = RackRole
fields = ('name', 'slug', 'color', 'description', 'tags') fields = ('name', 'slug', 'color', 'description', 'owner', 'tags')
class RackTypeImportForm(NetBoxModelImportForm): class RackTypeImportForm(PrimaryModelImportForm):
manufacturer = forms.ModelChoiceField( manufacturer = forms.ModelChoiceField(
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@@ -224,14 +226,14 @@ class RackTypeImportForm(NetBoxModelImportForm):
fields = ( fields = (
'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units',
'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight',
'weight_unit', 'description', 'comments', 'tags', 'weight_unit', 'description', 'owner', 'comments', 'tags',
) )
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
super().__init__(data, *args, **kwargs) super().__init__(data, *args, **kwargs)
class RackImportForm(NetBoxModelImportForm): class RackImportForm(PrimaryModelImportForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -309,7 +311,8 @@ class RackImportForm(NetBoxModelImportForm):
fields = ( fields = (
'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'rack_type', 'form_factor', 'serial', 'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'rack_type', 'form_factor', 'serial',
'asset_tag', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'asset_tag', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit',
'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', 'description', 'comments', 'tags', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'weight_unit', 'description', 'owner', 'comments',
'tags',
) )
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
@@ -332,7 +335,7 @@ class RackImportForm(NetBoxModelImportForm):
raise forms.ValidationError(_("U height must be set if not specifying a rack type.")) raise forms.ValidationError(_("U height must be set if not specifying a rack type."))
class RackReservationImportForm(NetBoxModelImportForm): class RackReservationImportForm(PrimaryModelImportForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -373,7 +376,7 @@ class RackReservationImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = RackReservation model = RackReservation
fields = ('site', 'location', 'rack', 'units', 'status', 'tenant', 'description', 'comments', 'tags') fields = ('site', 'location', 'rack', 'units', 'status', 'tenant', 'description', 'owner', 'comments', 'tags')
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
super().__init__(data, *args, **kwargs) super().__init__(data, *args, **kwargs)
@@ -392,14 +395,14 @@ class RackReservationImportForm(NetBoxModelImportForm):
self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params) self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params)
class ManufacturerImportForm(NetBoxModelImportForm): class ManufacturerImportForm(OrganizationalModelImportForm):
class Meta: class Meta:
model = Manufacturer model = Manufacturer
fields = ('name', 'slug', 'description', 'tags') fields = ('name', 'slug', 'description', 'owner', 'tags')
class DeviceTypeImportForm(NetBoxModelImportForm): class DeviceTypeImportForm(PrimaryModelImportForm):
manufacturer = CSVModelChoiceField( manufacturer = CSVModelChoiceField(
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@@ -429,20 +432,21 @@ class DeviceTypeImportForm(NetBoxModelImportForm):
model = DeviceType model = DeviceType
fields = [ fields = [
'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'u_height', 'exclude_from_utilization', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'u_height', 'exclude_from_utilization',
'is_full_depth', 'subdevice_role', 'airflow', 'description', 'weight', 'weight_unit', 'comments', 'tags', 'is_full_depth', 'subdevice_role', 'airflow', 'description', 'weight', 'weight_unit', 'owner', 'comments',
'tags',
] ]
class ModuleTypeProfileImportForm(NetBoxModelImportForm): class ModuleTypeProfileImportForm(PrimaryModelImportForm):
class Meta: class Meta:
model = ModuleTypeProfile model = ModuleTypeProfile
fields = [ fields = [
'name', 'description', 'schema', 'comments', 'tags', 'name', 'description', 'schema', 'owner', 'comments', 'tags',
] ]
class ModuleTypeImportForm(NetBoxModelImportForm): class ModuleTypeImportForm(PrimaryModelImportForm):
profile = forms.ModelChoiceField( profile = forms.ModelChoiceField(
label=_('Profile'), label=_('Profile'),
queryset=ModuleTypeProfile.objects.all(), queryset=ModuleTypeProfile.objects.all(),
@@ -476,11 +480,11 @@ class ModuleTypeImportForm(NetBoxModelImportForm):
model = ModuleType model = ModuleType
fields = [ fields = [
'manufacturer', 'model', 'part_number', 'description', 'airflow', 'weight', 'weight_unit', 'profile', 'manufacturer', 'model', 'part_number', 'description', 'airflow', 'weight', 'weight_unit', 'profile',
'comments', 'tags' 'owner', 'comments', 'tags'
] ]
class DeviceRoleImportForm(NetBoxModelImportForm): class DeviceRoleImportForm(NestedGroupModelImportForm):
parent = CSVModelChoiceField( parent = CSVModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
@@ -498,17 +502,15 @@ class DeviceRoleImportForm(NetBoxModelImportForm):
required=False, required=False,
help_text=_('Config template') help_text=_('Config template')
) )
slug = SlugField()
class Meta: class Meta:
model = DeviceRole model = DeviceRole
fields = ( fields = (
'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', 'comments', 'tags' 'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', 'owner', 'comments', 'tags'
) )
class PlatformImportForm(NetBoxModelImportForm): class PlatformImportForm(NestedGroupModelImportForm):
slug = SlugField()
parent = CSVModelChoiceField( parent = CSVModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
@@ -537,11 +539,11 @@ class PlatformImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = Platform model = Platform
fields = ( fields = (
'name', 'slug', 'parent', 'manufacturer', 'config_template', 'description', 'tags', 'name', 'slug', 'parent', 'manufacturer', 'config_template', 'description', 'owner', 'comments', 'tags',
) )
class BaseDeviceImportForm(NetBoxModelImportForm): class BaseDeviceImportForm(PrimaryModelImportForm):
role = CSVModelChoiceField( role = CSVModelChoiceField(
label=_('Device role'), label=_('Device role'),
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
@@ -667,8 +669,8 @@ class DeviceImportForm(BaseDeviceImportForm):
fields = [ fields = [
'name', 'role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status', 'name', 'role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status',
'site', 'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent', 'device_bay', 'airflow', 'site', 'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent', 'device_bay', 'airflow',
'virtual_chassis', 'vc_position', 'vc_priority', 'cluster', 'description', 'config_template', 'comments', 'virtual_chassis', 'vc_position', 'vc_priority', 'cluster', 'description', 'config_template', 'owner',
'tags', 'comments', 'tags',
] ]
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
@@ -715,7 +717,7 @@ class DeviceImportForm(BaseDeviceImportForm):
self.instance.parent_bay = device_bay self.instance.parent_bay = device_bay
class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm): class ModuleImportForm(ModuleCommonForm, PrimaryModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -753,7 +755,7 @@ class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm):
class Meta: class Meta:
model = Module model = Module
fields = ( fields = (
'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'status', 'description', 'comments', 'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'status', 'description', 'owner', 'comments',
'replicate_components', 'adopt_components', 'tags', 'replicate_components', 'adopt_components', 'tags',
) )
@@ -777,7 +779,7 @@ class ModuleImportForm(ModuleCommonForm, NetBoxModelImportForm):
# Device components # Device components
# #
class ConsolePortImportForm(NetBoxModelImportForm): class ConsolePortImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -800,10 +802,10 @@ class ConsolePortImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ConsolePort model = ConsolePort
fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'tags') fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'owner', 'tags')
class ConsoleServerPortImportForm(NetBoxModelImportForm): class ConsoleServerPortImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -826,10 +828,10 @@ class ConsoleServerPortImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ConsoleServerPort model = ConsoleServerPort
fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'tags') fields = ('device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'owner', 'tags')
class PowerPortImportForm(NetBoxModelImportForm): class PowerPortImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -845,11 +847,12 @@ class PowerPortImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = PowerPort model = PowerPort
fields = ( fields = (
'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description', 'tags' 'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description',
'owner', 'tags',
) )
class PowerOutletImportForm(NetBoxModelImportForm): class PowerOutletImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -879,7 +882,7 @@ class PowerOutletImportForm(NetBoxModelImportForm):
model = PowerOutlet model = PowerOutlet
fields = ( fields = (
'device', 'name', 'label', 'type', 'color', 'mark_connected', 'power_port', 'feed_leg', 'description', 'device', 'name', 'label', 'type', 'color', 'mark_connected', 'power_port', 'feed_leg', 'description',
'tags', 'owner', 'tags',
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -905,7 +908,7 @@ class PowerOutletImportForm(NetBoxModelImportForm):
self.fields['power_port'].queryset = PowerPort.objects.none() self.fields['power_port'].queryset = PowerPort.objects.none()
class InterfaceImportForm(NetBoxModelImportForm): class InterfaceImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -988,7 +991,7 @@ class InterfaceImportForm(NetBoxModelImportForm):
fields = ( fields = (
'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled', 'device', 'name', 'label', 'parent', 'bridge', 'lag', 'type', 'speed', 'duplex', 'enabled',
'mark_connected', 'wwn', 'vdcs', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode', 'mark_connected', 'wwn', 'vdcs', 'mtu', 'mgmt_only', 'description', 'poe_mode', 'poe_type', 'mode',
'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'tags' 'vrf', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'owner', 'tags'
) )
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
@@ -1023,7 +1026,7 @@ class InterfaceImportForm(NetBoxModelImportForm):
return self.cleaned_data['vdcs'] return self.cleaned_data['vdcs']
class FrontPortImportForm(NetBoxModelImportForm): class FrontPortImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1045,7 +1048,7 @@ class FrontPortImportForm(NetBoxModelImportForm):
model = FrontPort model = FrontPort
fields = ( fields = (
'device', 'name', 'label', 'type', 'color', 'mark_connected', 'rear_port', 'rear_port_position', 'device', 'name', 'label', 'type', 'color', 'mark_connected', 'rear_port', 'rear_port_position',
'description', 'tags' 'description', 'owner', 'tags'
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -1071,7 +1074,7 @@ class FrontPortImportForm(NetBoxModelImportForm):
self.fields['rear_port'].queryset = RearPort.objects.none() self.fields['rear_port'].queryset = RearPort.objects.none()
class RearPortImportForm(NetBoxModelImportForm): class RearPortImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1085,10 +1088,12 @@ class RearPortImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = RearPort model = RearPort
fields = ('device', 'name', 'label', 'type', 'color', 'mark_connected', 'positions', 'description', 'tags') fields = (
'device', 'name', 'label', 'type', 'color', 'mark_connected', 'positions', 'description', 'owner', 'tags',
)
class ModuleBayImportForm(NetBoxModelImportForm): class ModuleBayImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1097,10 +1102,10 @@ class ModuleBayImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ModuleBay model = ModuleBay
fields = ('device', 'name', 'label', 'position', 'description', 'tags') fields = ('device', 'name', 'label', 'position', 'description', 'owner', 'tags')
class DeviceBayImportForm(NetBoxModelImportForm): class DeviceBayImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1119,7 +1124,7 @@ class DeviceBayImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = DeviceBay model = DeviceBay
fields = ('device', 'name', 'label', 'installed_device', 'description', 'tags') fields = ('device', 'name', 'label', 'installed_device', 'description', 'owner', 'tags')
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
@@ -1148,7 +1153,7 @@ class DeviceBayImportForm(NetBoxModelImportForm):
self.fields['installed_device'].queryset = Device.objects.none() self.fields['installed_device'].queryset = Device.objects.none()
class InventoryItemImportForm(NetBoxModelImportForm): class InventoryItemImportForm(OwnerCSVMixin, NetBoxModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1195,7 +1200,7 @@ class InventoryItemImportForm(NetBoxModelImportForm):
model = InventoryItem model = InventoryItem
fields = ( fields = (
'device', 'name', 'label', 'status', 'role', 'manufacturer', 'parent', 'part_id', 'serial', 'asset_tag', 'device', 'name', 'label', 'status', 'role', 'manufacturer', 'parent', 'part_id', 'serial', 'asset_tag',
'discovered', 'description', 'tags', 'component_type', 'component_name', 'discovered', 'description', 'owner', 'tags', 'component_type', 'component_name',
) )
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -1258,7 +1263,7 @@ class InventoryItemImportForm(NetBoxModelImportForm):
# Device component roles # Device component roles
# #
class InventoryItemRoleImportForm(NetBoxModelImportForm): class InventoryItemRoleImportForm(OrganizationalModelImportForm):
slug = SlugField() slug = SlugField()
class Meta: class Meta:
@@ -1270,7 +1275,7 @@ class InventoryItemRoleImportForm(NetBoxModelImportForm):
# Addressing # Addressing
# #
class MACAddressImportForm(NetBoxModelImportForm): class MACAddressImportForm(PrimaryModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1301,7 +1306,8 @@ class MACAddressImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = MACAddress model = MACAddress
fields = [ fields = [
'mac_address', 'device', 'virtual_machine', 'interface', 'is_primary', 'description', 'comments', 'tags', 'mac_address', 'device', 'virtual_machine', 'interface', 'is_primary', 'description', 'owner', 'comments',
'tags',
] ]
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
@@ -1354,7 +1360,7 @@ class MACAddressImportForm(NetBoxModelImportForm):
# Cables # Cables
# #
class CableImportForm(NetBoxModelImportForm): class CableImportForm(PrimaryModelImportForm):
# Termination A # Termination A
side_a_site = CSVModelChoiceField( side_a_site = CSVModelChoiceField(
label=_('Side A site'), label=_('Side A site'),
@@ -1443,7 +1449,7 @@ class CableImportForm(NetBoxModelImportForm):
fields = [ fields = [
'side_a_site', 'side_a_device', 'side_a_type', 'side_a_name', 'side_b_site', 'side_b_device', 'side_b_type', 'side_a_site', 'side_a_device', 'side_a_type', 'side_a_name', 'side_b_site', 'side_b_device', 'side_b_type',
'side_b_name', 'type', 'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', 'side_b_name', 'type', 'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description',
'comments', 'tags', 'owner', 'comments', 'tags',
] ]
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
@@ -1537,7 +1543,7 @@ class CableImportForm(NetBoxModelImportForm):
# #
class VirtualChassisImportForm(NetBoxModelImportForm): class VirtualChassisImportForm(PrimaryModelImportForm):
master = CSVModelChoiceField( master = CSVModelChoiceField(
label=_('Master'), label=_('Master'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1548,14 +1554,14 @@ class VirtualChassisImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = VirtualChassis model = VirtualChassis
fields = ('name', 'domain', 'master', 'description', 'comments', 'tags') fields = ('name', 'domain', 'master', 'description', 'owner', 'comments', 'tags')
# #
# Power # Power
# #
class PowerPanelImportForm(NetBoxModelImportForm): class PowerPanelImportForm(PrimaryModelImportForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -1571,7 +1577,7 @@ class PowerPanelImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = PowerPanel model = PowerPanel
fields = ('site', 'location', 'name', 'description', 'comments', 'tags') fields = ('site', 'location', 'name', 'description', 'owner', 'comments', 'tags')
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
super().__init__(data, *args, **kwargs) super().__init__(data, *args, **kwargs)
@@ -1583,7 +1589,7 @@ class PowerPanelImportForm(NetBoxModelImportForm):
self.fields['location'].queryset = self.fields['location'].queryset.filter(**params) self.fields['location'].queryset = self.fields['location'].queryset.filter(**params)
class PowerFeedImportForm(NetBoxModelImportForm): class PowerFeedImportForm(PrimaryModelImportForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -1641,7 +1647,7 @@ class PowerFeedImportForm(NetBoxModelImportForm):
model = PowerFeed model = PowerFeed
fields = ( fields = (
'site', 'power_panel', 'location', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase', 'site', 'power_panel', 'location', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase',
'voltage', 'amperage', 'max_utilization', 'tenant', 'description', 'comments', 'tags', 'voltage', 'amperage', 'max_utilization', 'tenant', 'description', 'owner', 'comments', 'tags',
) )
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
@@ -1665,8 +1671,7 @@ class PowerFeedImportForm(NetBoxModelImportForm):
self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params) self.fields['rack'].queryset = self.fields['rack'].queryset.filter(**params)
class VirtualDeviceContextImportForm(NetBoxModelImportForm): class VirtualDeviceContextImportForm(PrimaryModelImportForm):
device = CSVModelChoiceField( device = CSVModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1701,7 +1706,7 @@ class VirtualDeviceContextImportForm(NetBoxModelImportForm):
class Meta: class Meta:
fields = [ fields = [
'name', 'device', 'status', 'tenant', 'identifier', 'comments', 'primary_ip4', 'primary_ip6', 'name', 'device', 'status', 'tenant', 'identifier', 'owner', 'comments', 'primary_ip4', 'primary_ip6',
] ]
model = VirtualDeviceContext model = VirtualDeviceContext

View File

@@ -8,11 +8,14 @@ from extras.forms import LocalConfigContextFilterForm
from extras.models import ConfigTemplate from extras.models import ConfigTemplate
from ipam.models import ASN, VRF, VLANTranslationPolicy from ipam.models import ASN, VRF, VLANTranslationPolicy
from netbox.choices import * from netbox.choices import *
from netbox.forms import NetBoxModelFilterSetForm from netbox.forms import (
NestedGroupModelFilterSetForm, NetBoxModelFilterSetForm, OrganizationalModelFilterSetForm,
PrimaryModelFilterSetForm,
)
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
from users.models import User from users.models import Owner, User
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
from utilities.forms.fields import ColorField, DynamicModelMultipleChoiceField, TagFilterField from utilities.forms.fields import ColorField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import NumberWithOptions from utilities.forms.widgets import NumberWithOptions
from virtualization.models import Cluster, ClusterGroup, VirtualMachine from virtualization.models import Cluster, ClusterGroup, VirtualMachine
@@ -137,12 +140,18 @@ class DeviceComponentFilterForm(NetBoxModelFilterSetForm):
required=False, required=False,
label=_('Device Status'), label=_('Device Status'),
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): class RegionFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
model = Region model = Region
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag', 'parent_id'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('parent_id', name=_('Region')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')) FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
) )
parent_id = DynamicModelMultipleChoiceField( parent_id = DynamicModelMultipleChoiceField(
@@ -153,10 +162,11 @@ class RegionFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): class SiteGroupFilterForm(ContactModelFilterForm, NestedGroupModelFilterSetForm):
model = SiteGroup model = SiteGroup
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag', 'parent_id'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('parent_id', name=_('Site Group')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')) FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
) )
parent_id = DynamicModelMultipleChoiceField( parent_id = DynamicModelMultipleChoiceField(
@@ -167,10 +177,10 @@ class SiteGroupFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm): class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, PrimaryModelFilterSetForm):
model = Site model = Site
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('status', 'region_id', 'group_id', 'asn_id', name=_('Attributes')), FieldSet('status', 'region_id', 'group_id', 'asn_id', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
@@ -199,10 +209,10 @@ class SiteFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte
tag = TagFilterField(model) tag = TagFilterField(model)
class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilterSetForm): class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NestedGroupModelFilterSetForm):
model = Location model = Location
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', 'parent_id', 'status', 'facility', name=_('Attributes')), FieldSet('region_id', 'site_group_id', 'site_id', 'parent_id', 'status', 'facility', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
@@ -247,12 +257,15 @@ class LocationFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelF
tag = TagFilterField(model) tag = TagFilterField(model)
class RackRoleFilterForm(NetBoxModelFilterSetForm): class RackRoleFilterForm(OrganizationalModelFilterSetForm):
model = RackRole model = RackRole
fieldsets = (
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
)
tag = TagFilterField(model) tag = TagFilterField(model)
class RackBaseFilterForm(NetBoxModelFilterSetForm): class RackBaseFilterForm(PrimaryModelFilterSetForm):
form_factor = forms.MultipleChoiceField( form_factor = forms.MultipleChoiceField(
label=_('Form factor'), label=_('Form factor'),
choices=RackFormFactorChoices, choices=RackFormFactorChoices,
@@ -303,7 +316,7 @@ class RackBaseFilterForm(NetBoxModelFilterSetForm):
class RackTypeFilterForm(RackBaseFilterForm): class RackTypeFilterForm(RackBaseFilterForm):
model = RackType model = RackType
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('manufacturer_id', 'form_factor', 'width', 'u_height', name=_('Rack Type')), FieldSet('manufacturer_id', 'form_factor', 'width', 'u_height', name=_('Rack Type')),
FieldSet('starting_unit', 'desc_units', name=_('Numbering')), FieldSet('starting_unit', 'desc_units', name=_('Numbering')),
FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')), FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
@@ -320,7 +333,7 @@ class RackTypeFilterForm(RackBaseFilterForm):
class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, RackBaseFilterForm): class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, RackBaseFilterForm):
model = Rack model = Rack
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('status', 'role_id', 'manufacturer_id', 'rack_type_id', 'serial', 'asset_tag', name=_('Rack')), FieldSet('status', 'role_id', 'manufacturer_id', 'rack_type_id', 'serial', 'asset_tag', name=_('Rack')),
@@ -413,10 +426,10 @@ class RackElevationFilterForm(RackFilterForm):
) )
class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class RackReservationFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = RackReservation model = RackReservation
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('status', 'user_id', name=_('Reservation')), FieldSet('status', 'user_id', name=_('Reservation')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Rack')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Rack')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
@@ -471,19 +484,19 @@ class RackReservationFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class ManufacturerFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): class ManufacturerFilterForm(ContactModelFilterForm, OrganizationalModelFilterSetForm):
model = Manufacturer model = Manufacturer
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')) FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts'))
) )
tag = TagFilterField(model) tag = TagFilterField(model)
class DeviceTypeFilterForm(NetBoxModelFilterSetForm): class DeviceTypeFilterForm(PrimaryModelFilterSetForm):
model = DeviceType model = DeviceType
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet( FieldSet(
'manufacturer_id', 'default_platform_id', 'part_number', 'subdevice_role', 'airflow', name=_('Hardware') 'manufacturer_id', 'default_platform_id', 'part_number', 'subdevice_role', 'airflow', name=_('Hardware')
), ),
@@ -608,18 +621,18 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
) )
class ModuleTypeProfileFilterForm(NetBoxModelFilterSetForm): class ModuleTypeProfileFilterForm(PrimaryModelFilterSetForm):
model = ModuleTypeProfile model = ModuleTypeProfile
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
) )
selector_fields = ('filter_id', 'q') selector_fields = ('filter_id', 'q')
class ModuleTypeFilterForm(NetBoxModelFilterSetForm): class ModuleTypeFilterForm(PrimaryModelFilterSetForm):
model = ModuleType model = ModuleType
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('profile_id', 'manufacturer_id', 'part_number', 'airflow', name=_('Hardware')), FieldSet('profile_id', 'manufacturer_id', 'part_number', 'airflow', name=_('Hardware')),
FieldSet( FieldSet(
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces', 'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
@@ -701,8 +714,12 @@ class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
) )
class DeviceRoleFilterForm(NetBoxModelFilterSetForm): class DeviceRoleFilterForm(NestedGroupModelFilterSetForm):
model = DeviceRole model = DeviceRole
fieldsets = (
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('parent_id', 'config_template_id', name=_('Device Role'))
)
config_template_id = DynamicModelMultipleChoiceField( config_template_id = DynamicModelMultipleChoiceField(
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
required=False, required=False,
@@ -716,8 +733,12 @@ class DeviceRoleFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class PlatformFilterForm(NetBoxModelFilterSetForm): class PlatformFilterForm(NestedGroupModelFilterSetForm):
model = Platform model = Platform
fieldsets = (
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('manufacturer_id', 'parent_id', 'config_template_id', name=_('Platform'))
)
selector_fields = ('filter_id', 'q', 'manufacturer_id') selector_fields = ('filter_id', 'q', 'manufacturer_id')
parent_id = DynamicModelMultipleChoiceField( parent_id = DynamicModelMultipleChoiceField(
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
@@ -741,11 +762,11 @@ class DeviceFilterForm(
LocalConfigContextFilterForm, LocalConfigContextFilterForm,
TenancyFilterForm, TenancyFilterForm,
ContactModelFilterForm, ContactModelFilterForm,
NetBoxModelFilterSetForm PrimaryModelFilterSetForm
): ):
model = Device model = Device
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address', name=_('Operation')), FieldSet('status', 'role_id', 'airflow', 'serial', 'asset_tag', 'mac_address', name=_('Operation')),
FieldSet('manufacturer_id', 'device_type_id', 'platform_id', name=_('Hardware')), FieldSet('manufacturer_id', 'device_type_id', 'platform_id', name=_('Hardware')),
@@ -935,13 +956,10 @@ class DeviceFilterForm(
tag = TagFilterField(model) tag = TagFilterField(model)
class VirtualDeviceContextFilterForm( class VirtualDeviceContextFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
TenancyFilterForm,
NetBoxModelFilterSetForm
):
model = VirtualDeviceContext model = VirtualDeviceContext
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('device', 'status', 'has_primary_ip', name=_('Attributes')), FieldSet('device', 'status', 'has_primary_ip', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
) )
@@ -965,10 +983,10 @@ class VirtualDeviceContextFilterForm(
tag = TagFilterField(model) tag = TagFilterField(model)
class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm): class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = Module model = Module
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')),
FieldSet('manufacturer_id', 'module_type_id', 'status', 'serial', 'asset_tag', name=_('Hardware')), FieldSet('manufacturer_id', 'module_type_id', 'status', 'serial', 'asset_tag', name=_('Hardware')),
) )
@@ -1048,10 +1066,10 @@ class ModuleFilterForm(LocalConfigContextFilterForm, TenancyFilterForm, NetBoxMo
tag = TagFilterField(model) tag = TagFilterField(model)
class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class VirtualChassisFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = VirtualChassis model = VirtualChassis
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
) )
@@ -1077,10 +1095,10 @@ class VirtualChassisFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class CableFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = Cable model = Cable
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')), FieldSet('site_id', 'location_id', 'rack_id', 'device_id', name=_('Location')),
FieldSet('type', 'status', 'color', 'length', 'length_unit', 'unterminated', name=_('Attributes')), FieldSet('type', 'status', 'color', 'length', 'length_unit', 'unterminated', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
@@ -1161,10 +1179,10 @@ class CableFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm): class PowerPanelFilterForm(ContactModelFilterForm, PrimaryModelFilterSetForm):
model = PowerPanel model = PowerPanel
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', name=_('Location')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
) )
@@ -1200,10 +1218,10 @@ class PowerPanelFilterForm(ContactModelFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class PowerFeedFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class PowerFeedFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = PowerFeed model = PowerFeed
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'power_panel_id', 'rack_id', name=_('Location')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization', name=_('Attributes')), FieldSet('status', 'type', 'supply', 'phase', 'voltage', 'amperage', 'max_utilization', name=_('Attributes')),
@@ -1313,7 +1331,7 @@ class PathEndpointFilterForm(CabledFilterForm):
class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = ConsolePort model = ConsolePort
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')), FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet( FieldSet(
@@ -1337,7 +1355,7 @@ class ConsolePortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = ConsoleServerPort model = ConsoleServerPort
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')), FieldSet('name', 'label', 'type', 'speed', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet( FieldSet(
@@ -1362,7 +1380,7 @@ class ConsoleServerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterF
class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = PowerPort model = PowerPort
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', 'type', name=_('Attributes')), FieldSet('name', 'label', 'type', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet( FieldSet(
@@ -1381,7 +1399,7 @@ class PowerPortFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = PowerOutlet model = PowerOutlet
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', 'type', 'color', 'status', name=_('Attributes')), FieldSet('name', 'label', 'type', 'color', 'status', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet( FieldSet(
@@ -1410,7 +1428,7 @@ class PowerOutletFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm): class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
model = Interface model = Interface
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only', name=_('Attributes')), FieldSet('name', 'label', 'kind', 'type', 'speed', 'duplex', 'enabled', 'mgmt_only', name=_('Attributes')),
FieldSet('vrf_id', 'l2vpn_id', 'mac_address', 'wwn', name=_('Addressing')), FieldSet('vrf_id', 'l2vpn_id', 'mac_address', 'wwn', name=_('Addressing')),
FieldSet('poe_mode', 'poe_type', name=_('PoE')), FieldSet('poe_mode', 'poe_type', name=_('PoE')),
@@ -1535,7 +1553,7 @@ class InterfaceFilterForm(PathEndpointFilterForm, DeviceComponentFilterForm):
class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', 'type', 'color', name=_('Attributes')), FieldSet('name', 'label', 'type', 'color', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet( FieldSet(
@@ -1559,7 +1577,7 @@ class FrontPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm): class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
model = RearPort model = RearPort
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', 'type', 'color', name=_('Attributes')), FieldSet('name', 'label', 'type', 'color', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet( FieldSet(
@@ -1583,7 +1601,7 @@ class RearPortFilterForm(CabledFilterForm, DeviceComponentFilterForm):
class ModuleBayFilterForm(DeviceComponentFilterForm): class ModuleBayFilterForm(DeviceComponentFilterForm):
model = ModuleBay model = ModuleBay
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', 'position', name=_('Attributes')), FieldSet('name', 'label', 'position', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet( FieldSet(
@@ -1601,7 +1619,7 @@ class ModuleBayFilterForm(DeviceComponentFilterForm):
class DeviceBayFilterForm(DeviceComponentFilterForm): class DeviceBayFilterForm(DeviceComponentFilterForm):
model = DeviceBay model = DeviceBay
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'label', name=_('Attributes')), FieldSet('name', 'label', name=_('Attributes')),
FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', 'location_id', 'rack_id', name=_('Location')),
FieldSet( FieldSet(
@@ -1615,7 +1633,7 @@ class DeviceBayFilterForm(DeviceComponentFilterForm):
class InventoryItemFilterForm(DeviceComponentFilterForm): class InventoryItemFilterForm(DeviceComponentFilterForm):
model = InventoryItem model = InventoryItem
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet( FieldSet(
'name', 'label', 'status', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered', 'name', 'label', 'status', 'role_id', 'manufacturer_id', 'serial', 'asset_tag', 'discovered',
name=_('Attributes') name=_('Attributes')
@@ -1663,8 +1681,11 @@ class InventoryItemFilterForm(DeviceComponentFilterForm):
# Device component roles # Device component roles
# #
class InventoryItemRoleFilterForm(NetBoxModelFilterSetForm): class InventoryItemRoleFilterForm(OrganizationalModelFilterSetForm):
model = InventoryItemRole model = InventoryItemRole
fieldsets = (
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
)
tag = TagFilterField(model) tag = TagFilterField(model)
@@ -1672,10 +1693,10 @@ class InventoryItemRoleFilterForm(NetBoxModelFilterSetForm):
# Addressing # Addressing
# #
class MACAddressFilterForm(NetBoxModelFilterSetForm): class MACAddressFilterForm(PrimaryModelFilterSetForm):
model = MACAddress model = MACAddress
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('mac_address', 'device_id', 'virtual_machine_id', name=_('MAC address')), FieldSet('mac_address', 'device_id', 'virtual_machine_id', name=_('MAC address')),
) )
selector_fields = ('filter_id', 'q', 'device_id', 'virtual_machine_id') selector_fields = ('filter_id', 'q', 'device_id', 'virtual_machine_id')

View File

@@ -10,13 +10,13 @@ from dcim.models import *
from extras.models import ConfigTemplate from extras.models import ConfigTemplate
from ipam.choices import VLANQinQRoleChoices from ipam.choices import VLANQinQRoleChoices
from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VLANTranslationPolicy, VRF from ipam.models import ASN, IPAddress, VLAN, VLANGroup, VLANTranslationPolicy, VRF
from netbox.forms import NetBoxModelForm from netbox.forms import NestedGroupModelForm, NetBoxModelForm, OrganizationalModelForm, PrimaryModelForm
from netbox.forms.mixins import ChangelogMessageMixin from netbox.forms.mixins import ChangelogMessageMixin, OwnerMixin
from tenancy.forms import TenancyForm from tenancy.forms import TenancyForm
from users.models import User from users.models import User
from utilities.forms import add_blank_choice, get_field_value from utilities.forms import add_blank_choice, get_field_value
from utilities.forms.fields import ( from utilities.forms.fields import (
CommentField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, NumericArrayField, SlugField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, JSONField, NumericArrayField, SlugField,
) )
from utilities.forms.rendering import FieldSet, InlineFields, TabbedGroups from utilities.forms.rendering import FieldSet, InlineFields, TabbedGroups
from utilities.forms.widgets import APISelect, ClearableFileInput, HTMXSelect, NumberWithOptions, SelectWithPK from utilities.forms.widgets import APISelect, ClearableFileInput, HTMXSelect, NumberWithOptions, SelectWithPK
@@ -75,14 +75,12 @@ __all__ = (
) )
class RegionForm(NetBoxModelForm): class RegionForm(NestedGroupModelForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=Region.objects.all(), queryset=Region.objects.all(),
required=False required=False
) )
slug = SlugField()
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('parent', 'name', 'slug', 'description', 'tags'), FieldSet('parent', 'name', 'slug', 'description', 'tags'),
@@ -91,18 +89,16 @@ class RegionForm(NetBoxModelForm):
class Meta: class Meta:
model = Region model = Region
fields = ( fields = (
'parent', 'name', 'slug', 'description', 'tags', 'comments', 'parent', 'name', 'slug', 'description', 'owner', 'tags', 'comments',
) )
class SiteGroupForm(NetBoxModelForm): class SiteGroupForm(NestedGroupModelForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=SiteGroup.objects.all(), queryset=SiteGroup.objects.all(),
required=False required=False
) )
slug = SlugField()
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('parent', 'name', 'slug', 'description', 'tags'), FieldSet('parent', 'name', 'slug', 'description', 'tags'),
@@ -111,11 +107,11 @@ class SiteGroupForm(NetBoxModelForm):
class Meta: class Meta:
model = SiteGroup model = SiteGroup
fields = ( fields = (
'parent', 'name', 'slug', 'description', 'comments', 'tags', 'parent', 'name', 'slug', 'description', 'owner', 'comments', 'tags',
) )
class SiteForm(TenancyForm, NetBoxModelForm): class SiteForm(TenancyForm, PrimaryModelForm):
region = DynamicModelChoiceField( region = DynamicModelChoiceField(
label=_('Region'), label=_('Region'),
queryset=Region.objects.all(), queryset=Region.objects.all(),
@@ -139,7 +135,6 @@ class SiteForm(TenancyForm, NetBoxModelForm):
choices=add_blank_choice(TimeZoneFormField().choices), choices=add_blank_choice(TimeZoneFormField().choices),
required=False required=False
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -154,7 +149,7 @@ class SiteForm(TenancyForm, NetBoxModelForm):
model = Site model = Site
fields = ( fields = (
'name', 'slug', 'status', 'region', 'group', 'tenant_group', 'tenant', 'facility', 'asns', 'time_zone', 'name', 'slug', 'status', 'region', 'group', 'tenant_group', 'tenant', 'facility', 'asns', 'time_zone',
'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'tags', 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'owner', 'comments', 'tags',
) )
widgets = { widgets = {
'physical_address': forms.Textarea( 'physical_address': forms.Textarea(
@@ -170,7 +165,7 @@ class SiteForm(TenancyForm, NetBoxModelForm):
} }
class LocationForm(TenancyForm, NetBoxModelForm): class LocationForm(TenancyForm, NestedGroupModelForm):
site = DynamicModelChoiceField( site = DynamicModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -184,8 +179,6 @@ class LocationForm(TenancyForm, NetBoxModelForm):
'site_id': '$site' 'site_id': '$site'
} }
) )
slug = SlugField()
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('site', 'parent', 'name', 'slug', 'status', 'facility', 'description', 'tags', name=_('Location')), FieldSet('site', 'parent', 'name', 'slug', 'status', 'facility', 'description', 'tags', name=_('Location')),
@@ -195,14 +188,12 @@ class LocationForm(TenancyForm, NetBoxModelForm):
class Meta: class Meta:
model = Location model = Location
fields = ( fields = (
'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant', 'site', 'parent', 'name', 'slug', 'status', 'description', 'tenant_group', 'tenant', 'facility', 'owner',
'facility', 'tags', 'comments', 'comments', 'tags',
) )
class RackRoleForm(NetBoxModelForm): class RackRoleForm(OrganizationalModelForm):
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'color', 'description', 'tags', name=_('Rack Role')), FieldSet('name', 'slug', 'color', 'description', 'tags', name=_('Rack Role')),
) )
@@ -210,17 +201,16 @@ class RackRoleForm(NetBoxModelForm):
class Meta: class Meta:
model = RackRole model = RackRole
fields = [ fields = [
'name', 'slug', 'color', 'description', 'tags', 'name', 'slug', 'color', 'description', 'owner', 'tags',
] ]
class RackTypeForm(NetBoxModelForm): class RackTypeForm(PrimaryModelForm):
manufacturer = DynamicModelChoiceField( manufacturer = DynamicModelChoiceField(
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
quick_add=True quick_add=True
) )
comments = CommentField()
slug = SlugField( slug = SlugField(
label=_('Slug'), label=_('Slug'),
slug_source='model' slug_source='model'
@@ -242,11 +232,11 @@ class RackTypeForm(NetBoxModelForm):
fields = [ fields = [
'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'manufacturer', 'model', 'slug', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units',
'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'outer_width', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight',
'weight_unit', 'description', 'comments', 'tags', 'weight_unit', 'description', 'owner', 'comments', 'tags',
] ]
class RackForm(TenancyForm, NetBoxModelForm): class RackForm(TenancyForm, PrimaryModelForm):
site = DynamicModelChoiceField( site = DynamicModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -271,7 +261,6 @@ class RackForm(TenancyForm, NetBoxModelForm):
required=False, required=False,
help_text=_("Select a pre-defined rack type, or set physical characteristics below.") help_text=_("Select a pre-defined rack type, or set physical characteristics below.")
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -288,7 +277,7 @@ class RackForm(TenancyForm, NetBoxModelForm):
'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial', 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial',
'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width', 'asset_tag', 'rack_type', 'form_factor', 'width', 'u_height', 'starting_unit', 'desc_units', 'outer_width',
'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight', 'outer_height', 'outer_depth', 'outer_unit', 'mounting_depth', 'airflow', 'weight', 'max_weight',
'weight_unit', 'description', 'comments', 'tags', 'weight_unit', 'description', 'owner', 'comments', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -318,7 +307,7 @@ class RackForm(TenancyForm, NetBoxModelForm):
) )
class RackReservationForm(TenancyForm, NetBoxModelForm): class RackReservationForm(TenancyForm, PrimaryModelForm):
rack = DynamicModelChoiceField( rack = DynamicModelChoiceField(
label=_('Rack'), label=_('Rack'),
queryset=Rack.objects.all(), queryset=Rack.objects.all(),
@@ -333,7 +322,6 @@ class RackReservationForm(TenancyForm, NetBoxModelForm):
label=_('User'), label=_('User'),
queryset=User.objects.order_by('username') queryset=User.objects.order_by('username')
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('rack', 'units', 'status', 'user', 'description', 'tags', name=_('Reservation')), FieldSet('rack', 'units', 'status', 'user', 'description', 'tags', name=_('Reservation')),
@@ -343,13 +331,11 @@ class RackReservationForm(TenancyForm, NetBoxModelForm):
class Meta: class Meta:
model = RackReservation model = RackReservation
fields = [ fields = [
'rack', 'units', 'status', 'user', 'tenant_group', 'tenant', 'description', 'comments', 'tags', 'rack', 'units', 'status', 'user', 'tenant_group', 'tenant', 'description', 'owner', 'comments', 'tags',
] ]
class ManufacturerForm(NetBoxModelForm): class ManufacturerForm(OrganizationalModelForm):
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'description', 'tags', name=_('Manufacturer')), FieldSet('name', 'slug', 'description', 'tags', name=_('Manufacturer')),
) )
@@ -357,11 +343,11 @@ class ManufacturerForm(NetBoxModelForm):
class Meta: class Meta:
model = Manufacturer model = Manufacturer
fields = [ fields = [
'name', 'slug', 'description', 'tags', 'name', 'slug', 'description', 'owner', 'tags',
] ]
class DeviceTypeForm(NetBoxModelForm): class DeviceTypeForm(PrimaryModelForm):
manufacturer = DynamicModelChoiceField( manufacturer = DynamicModelChoiceField(
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all(), queryset=Manufacturer.objects.all(),
@@ -380,7 +366,6 @@ class DeviceTypeForm(NetBoxModelForm):
label=_('Slug'), label=_('Slug'),
slug_source='model' slug_source='model'
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('manufacturer', 'model', 'slug', 'default_platform', 'description', 'tags', name=_('Device Type')), FieldSet('manufacturer', 'model', 'slug', 'default_platform', 'description', 'tags', name=_('Device Type')),
@@ -396,7 +381,7 @@ class DeviceTypeForm(NetBoxModelForm):
fields = [ fields = [
'manufacturer', 'model', 'slug', 'default_platform', 'part_number', 'u_height', 'exclude_from_utilization', 'manufacturer', 'model', 'slug', 'default_platform', 'part_number', 'u_height', 'exclude_from_utilization',
'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image',
'description', 'comments', 'tags', 'description', 'owner', 'comments', 'tags',
] ]
widgets = { widgets = {
'front_image': ClearableFileInput(attrs={ 'front_image': ClearableFileInput(attrs={
@@ -408,13 +393,12 @@ class DeviceTypeForm(NetBoxModelForm):
} }
class ModuleTypeProfileForm(NetBoxModelForm): class ModuleTypeProfileForm(PrimaryModelForm):
schema = JSONField( schema = JSONField(
label=_('Schema'), label=_('Schema'),
required=False, required=False,
help_text=_("Enter a valid JSON schema to define supported attributes.") help_text=_("Enter a valid JSON schema to define supported attributes.")
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('name', 'description', 'schema', 'tags', name=_('Profile')), FieldSet('name', 'description', 'schema', 'tags', name=_('Profile')),
@@ -423,11 +407,11 @@ class ModuleTypeProfileForm(NetBoxModelForm):
class Meta: class Meta:
model = ModuleTypeProfile model = ModuleTypeProfile
fields = [ fields = [
'name', 'description', 'schema', 'comments', 'tags', 'name', 'description', 'schema', 'owner', 'comments', 'tags',
] ]
class ModuleTypeForm(NetBoxModelForm): class ModuleTypeForm(PrimaryModelForm):
profile = forms.ModelChoiceField( profile = forms.ModelChoiceField(
queryset=ModuleTypeProfile.objects.all(), queryset=ModuleTypeProfile.objects.all(),
label=_('Profile'), label=_('Profile'),
@@ -438,7 +422,6 @@ class ModuleTypeForm(NetBoxModelForm):
label=_('Manufacturer'), label=_('Manufacturer'),
queryset=Manufacturer.objects.all() queryset=Manufacturer.objects.all()
) )
comments = CommentField()
@property @property
def fieldsets(self): def fieldsets(self):
@@ -452,7 +435,7 @@ class ModuleTypeForm(NetBoxModelForm):
model = ModuleType model = ModuleType
fields = [ fields = [
'profile', 'manufacturer', 'model', 'part_number', 'description', 'airflow', 'weight', 'weight_unit', 'profile', 'manufacturer', 'model', 'part_number', 'description', 'airflow', 'weight', 'weight_unit',
'comments', 'tags', 'owner', 'comments', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -507,19 +490,17 @@ class ModuleTypeForm(NetBoxModelForm):
return super()._post_clean() return super()._post_clean()
class DeviceRoleForm(NetBoxModelForm): class DeviceRoleForm(NestedGroupModelForm):
config_template = DynamicModelChoiceField( config_template = DynamicModelChoiceField(
label=_('Config template'), label=_('Config template'),
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
required=False required=False
) )
slug = SlugField()
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=DeviceRole.objects.all(), queryset=DeviceRole.objects.all(),
required=False, required=False,
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -531,11 +512,11 @@ class DeviceRoleForm(NetBoxModelForm):
class Meta: class Meta:
model = DeviceRole model = DeviceRole
fields = [ fields = [
'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', 'comments', 'tags', 'name', 'slug', 'parent', 'color', 'vm_role', 'config_template', 'description', 'owner', 'comments', 'tags',
] ]
class PlatformForm(NetBoxModelForm): class PlatformForm(NestedGroupModelForm):
parent = DynamicModelChoiceField( parent = DynamicModelChoiceField(
label=_('Parent'), label=_('Parent'),
queryset=Platform.objects.all(), queryset=Platform.objects.all(),
@@ -556,7 +537,6 @@ class PlatformForm(NetBoxModelForm):
label=_('Slug'), label=_('Slug'),
max_length=64 max_length=64
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -567,11 +547,11 @@ class PlatformForm(NetBoxModelForm):
class Meta: class Meta:
model = Platform model = Platform
fields = [ fields = [
'name', 'slug', 'parent', 'manufacturer', 'config_template', 'description', 'comments', 'tags', 'name', 'slug', 'parent', 'manufacturer', 'config_template', 'description', 'owner', 'comments', 'tags',
] ]
class DeviceForm(TenancyForm, NetBoxModelForm): class DeviceForm(TenancyForm, PrimaryModelForm):
site = DynamicModelChoiceField( site = DynamicModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -641,7 +621,6 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
'site_id': ['$site', 'null'] 'site_id': ['$site', 'null']
}, },
) )
comments = CommentField()
local_context_data = JSONField( local_context_data = JSONField(
required=False, required=False,
label='' label=''
@@ -677,7 +656,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
'name', 'role', 'device_type', 'serial', 'asset_tag', 'site', 'rack', 'location', 'position', 'face', 'name', 'role', 'device_type', 'serial', 'asset_tag', 'site', 'rack', 'location', 'position', 'face',
'latitude', 'longitude', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'latitude', 'longitude', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster',
'tenant_group', 'tenant', 'virtual_chassis', 'vc_position', 'vc_priority', 'description', 'config_template', 'tenant_group', 'tenant', 'virtual_chassis', 'vc_position', 'vc_priority', 'description', 'config_template',
'comments', 'tags', 'local_context_data', 'owner', 'comments', 'tags', 'local_context_data',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -742,7 +721,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm):
self.fields['position'].widget.choices = [(position, f'U{position}')] self.fields['position'].widget.choices = [(position, f'U{position}')]
class ModuleForm(ModuleCommonForm, NetBoxModelForm): class ModuleForm(ModuleCommonForm, PrimaryModelForm):
device = DynamicModelChoiceField( device = DynamicModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -765,7 +744,6 @@ class ModuleForm(ModuleCommonForm, NetBoxModelForm):
}, },
selector=True selector=True
) )
comments = CommentField()
replicate_components = forms.BooleanField( replicate_components = forms.BooleanField(
label=_('Replicate components'), label=_('Replicate components'),
required=False, required=False,
@@ -788,7 +766,7 @@ class ModuleForm(ModuleCommonForm, NetBoxModelForm):
model = Module model = Module
fields = [ fields = [
'device', 'module_bay', 'module_type', 'status', 'serial', 'asset_tag', 'tags', 'replicate_components', 'device', 'module_bay', 'module_type', 'status', 'serial', 'asset_tag', 'tags', 'replicate_components',
'adopt_components', 'description', 'comments', 'adopt_components', 'description', 'owner', 'comments',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -809,7 +787,7 @@ def get_termination_type_choices():
]) ])
class CableForm(TenancyForm, NetBoxModelForm): class CableForm(TenancyForm, PrimaryModelForm):
a_terminations_type = forms.ChoiceField( a_terminations_type = forms.ChoiceField(
choices=get_termination_type_choices, choices=get_termination_type_choices,
required=False, required=False,
@@ -822,17 +800,16 @@ class CableForm(TenancyForm, NetBoxModelForm):
widget=HTMXSelect(), widget=HTMXSelect(),
label=_('Type') label=_('Type')
) )
comments = CommentField()
class Meta: class Meta:
model = Cable model = Cable
fields = [ fields = [
'a_terminations_type', 'b_terminations_type', 'type', 'status', 'tenant_group', 'tenant', 'label', 'color', 'a_terminations_type', 'b_terminations_type', 'type', 'status', 'tenant_group', 'tenant', 'label', 'color',
'length', 'length_unit', 'description', 'comments', 'tags', 'length', 'length_unit', 'description', 'owner', 'comments', 'tags',
] ]
class PowerPanelForm(NetBoxModelForm): class PowerPanelForm(PrimaryModelForm):
site = DynamicModelChoiceField( site = DynamicModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -846,7 +823,6 @@ class PowerPanelForm(NetBoxModelForm):
'site_id': '$site' 'site_id': '$site'
} }
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('site', 'location', 'name', 'description', 'tags', name=_('Power Panel')), FieldSet('site', 'location', 'name', 'description', 'tags', name=_('Power Panel')),
@@ -855,11 +831,11 @@ class PowerPanelForm(NetBoxModelForm):
class Meta: class Meta:
model = PowerPanel model = PowerPanel
fields = [ fields = [
'site', 'location', 'name', 'description', 'comments', 'tags', 'site', 'location', 'name', 'description', 'owner', 'comments', 'tags',
] ]
class PowerFeedForm(TenancyForm, NetBoxModelForm): class PowerFeedForm(TenancyForm, PrimaryModelForm):
power_panel = DynamicModelChoiceField( power_panel = DynamicModelChoiceField(
label=_('Power panel'), label=_('Power panel'),
queryset=PowerPanel.objects.all(), queryset=PowerPanel.objects.all(),
@@ -872,7 +848,6 @@ class PowerFeedForm(TenancyForm, NetBoxModelForm):
required=False, required=False,
selector=True selector=True
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -887,7 +862,7 @@ class PowerFeedForm(TenancyForm, NetBoxModelForm):
model = PowerFeed model = PowerFeed
fields = [ fields = [
'power_panel', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage', 'power_panel', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage',
'max_utilization', 'tenant_group', 'tenant', 'description', 'comments', 'tags' 'max_utilization', 'tenant_group', 'tenant', 'description', 'owner', 'comments', 'tags'
] ]
@@ -895,18 +870,17 @@ class PowerFeedForm(TenancyForm, NetBoxModelForm):
# Virtual chassis # Virtual chassis
# #
class VirtualChassisForm(NetBoxModelForm): class VirtualChassisForm(PrimaryModelForm):
master = forms.ModelChoiceField( master = forms.ModelChoiceField(
label=_('Master'), label=_('Master'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
required=False, required=False,
) )
comments = CommentField()
class Meta: class Meta:
model = VirtualChassis model = VirtualChassis
fields = [ fields = [
'name', 'domain', 'master', 'description', 'comments', 'tags', 'name', 'domain', 'master', 'description', 'owner', 'comments', 'tags',
] ]
widgets = { widgets = {
'master': SelectWithPK(), 'master': SelectWithPK(),
@@ -1360,7 +1334,7 @@ class InventoryItemTemplateForm(ComponentTemplateForm):
# Device components # Device components
# #
class DeviceComponentForm(NetBoxModelForm): class DeviceComponentForm(OwnerMixin, NetBoxModelForm):
device = DynamicModelChoiceField( device = DynamicModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1396,7 +1370,7 @@ class ConsolePortForm(ModularDeviceComponentForm):
class Meta: class Meta:
model = ConsolePort model = ConsolePort
fields = [ fields = [
'device', 'module', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'tags', 'device', 'module', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'owner', 'tags',
] ]
@@ -1410,7 +1384,7 @@ class ConsoleServerPortForm(ModularDeviceComponentForm):
class Meta: class Meta:
model = ConsoleServerPort model = ConsoleServerPort
fields = [ fields = [
'device', 'module', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'tags', 'device', 'module', 'name', 'label', 'type', 'speed', 'mark_connected', 'description', 'owner', 'tags',
] ]
@@ -1426,7 +1400,7 @@ class PowerPortForm(ModularDeviceComponentForm):
model = PowerPort model = PowerPort
fields = [ fields = [
'device', 'module', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'mark_connected', 'device', 'module', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'mark_connected',
'description', 'tags', 'description', 'owner', 'tags',
] ]
@@ -1443,7 +1417,7 @@ class PowerOutletForm(ModularDeviceComponentForm):
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
'device', 'module', 'name', 'label', 'type', 'status', 'color', 'power_port', 'feed_leg', 'mark_connected', 'device', 'module', 'name', 'label', 'type', 'status', 'color', 'power_port', 'feed_leg', 'mark_connected',
'description', 'tags', 'description', 'owner', 'tags',
), ),
) )
@@ -1587,7 +1561,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
'lag', 'wwn', 'mtu', 'mgmt_only', 'mark_connected', 'description', 'poe_mode', 'poe_type', 'mode', 'lag', 'wwn', 'mtu', 'mgmt_only', 'mark_connected', 'description', 'poe_mode', 'poe_type', 'mode',
'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'wireless_lans', 'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'wireless_lans',
'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'vlan_translation_policy', 'vrf', 'primary_mac_address', 'untagged_vlan', 'tagged_vlans', 'qinq_svlan', 'vlan_translation_policy', 'vrf', 'primary_mac_address',
'tags', 'owner', 'tags',
] ]
widgets = { widgets = {
'speed': NumberWithOptions( 'speed': NumberWithOptions(
@@ -1619,7 +1593,7 @@ class FrontPortForm(ModularDeviceComponentForm):
model = FrontPort model = FrontPort
fields = [ fields = [
'device', 'module', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'mark_connected', 'device', 'module', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'mark_connected',
'description', 'tags', 'description', 'owner', 'tags',
] ]
@@ -1633,7 +1607,8 @@ class RearPortForm(ModularDeviceComponentForm):
class Meta: class Meta:
model = RearPort model = RearPort
fields = [ fields = [
'device', 'module', 'name', 'label', 'type', 'color', 'positions', 'mark_connected', 'description', 'tags', 'device', 'module', 'name', 'label', 'type', 'color', 'positions', 'mark_connected', 'description', 'owner',
'tags',
] ]
@@ -1645,7 +1620,7 @@ class ModuleBayForm(ModularDeviceComponentForm):
class Meta: class Meta:
model = ModuleBay model = ModuleBay
fields = [ fields = [
'device', 'module', 'name', 'label', 'position', 'description', 'tags', 'device', 'module', 'name', 'label', 'position', 'description', 'owner', 'tags',
] ]
@@ -1657,7 +1632,7 @@ class DeviceBayForm(DeviceComponentForm):
class Meta: class Meta:
model = DeviceBay model = DeviceBay
fields = [ fields = [
'device', 'name', 'label', 'description', 'tags', 'device', 'name', 'label', 'description', 'owner', 'tags',
] ]
@@ -1782,7 +1757,7 @@ class InventoryItemForm(DeviceComponentForm):
model = InventoryItem model = InventoryItem
fields = [ fields = [
'device', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'device', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag',
'status', 'description', 'tags', 'status', 'description', 'owner', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -1828,12 +1803,7 @@ class InventoryItemForm(DeviceComponentForm):
self.instance.component = None self.instance.component = None
# Device component roles class InventoryItemRoleForm(OrganizationalModelForm):
#
class InventoryItemRoleForm(NetBoxModelForm):
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'color', 'description', 'tags', name=_('Inventory Item Role')), FieldSet('name', 'slug', 'color', 'description', 'tags', name=_('Inventory Item Role')),
) )
@@ -1841,11 +1811,11 @@ class InventoryItemRoleForm(NetBoxModelForm):
class Meta: class Meta:
model = InventoryItemRole model = InventoryItemRole
fields = [ fields = [
'name', 'slug', 'color', 'description', 'tags', 'name', 'slug', 'color', 'description', 'owner', 'tags',
] ]
class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm): class VirtualDeviceContextForm(TenancyForm, PrimaryModelForm):
device = DynamicModelChoiceField( device = DynamicModelChoiceField(
label=_('Device'), label=_('Device'),
queryset=Device.objects.all(), queryset=Device.objects.all(),
@@ -1881,7 +1851,7 @@ class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm):
class Meta: class Meta:
model = VirtualDeviceContext model = VirtualDeviceContext
fields = [ fields = [
'device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant', 'device', 'name', 'status', 'identifier', 'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant', 'owner',
'comments', 'tags' 'comments', 'tags'
] ]
@@ -1890,7 +1860,7 @@ class VirtualDeviceContextForm(TenancyForm, NetBoxModelForm):
# Addressing # Addressing
# #
class MACAddressForm(NetBoxModelForm): class MACAddressForm(PrimaryModelForm):
mac_address = forms.CharField( mac_address = forms.CharField(
required=True, required=True,
label=_('MAC address') label=_('MAC address')
@@ -1929,7 +1899,7 @@ class MACAddressForm(NetBoxModelForm):
class Meta: class Meta:
model = MACAddress model = MACAddress
fields = [ fields = [
'mac_address', 'interface', 'vminterface', 'description', 'tags', 'mac_address', 'interface', 'vminterface', 'description', 'owner', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):

View File

@@ -434,8 +434,8 @@ class VirtualChassisCreateForm(NetBoxModelForm):
class Meta: class Meta:
model = VirtualChassis model = VirtualChassis
fields = [ fields = [
'name', 'domain', 'description', 'region', 'site_group', 'site', 'rack', 'members', 'initial_position', 'name', 'domain', 'description', 'region', 'site_group', 'site', 'rack', 'owner', 'members',
'tags', 'initial_position', 'tags',
] ]
def clean(self): def clean(self):

View File

@@ -5,16 +5,13 @@ import strawberry_django
from core.graphql.mixins import ChangelogMixin from core.graphql.mixins import ChangelogMixin
from dcim import models from dcim import models
from extras.graphql.mixins import ( from extras.graphql.mixins import ConfigContextMixin, ContactsMixin, ImageAttachmentsMixin
ConfigContextMixin,
ContactsMixin,
CustomFieldsMixin,
ImageAttachmentsMixin,
TagsMixin,
)
from ipam.graphql.mixins import IPAddressesMixin, VLANGroupsMixin from ipam.graphql.mixins import IPAddressesMixin, VLANGroupsMixin
from netbox.graphql.scalars import BigInt from netbox.graphql.scalars import BigInt
from netbox.graphql.types import BaseObjectType, NetBoxObjectType, OrganizationalObjectType from netbox.graphql.types import (
BaseObjectType, NestedGroupObjectType, NetBoxObjectType, OrganizationalObjectType, PrimaryObjectType,
)
from users.graphql.mixins import OwnerMixin
from .filters import * from .filters import *
from .mixins import CabledObjectMixin, PathEndpointMixin from .mixins import CabledObjectMixin, PathEndpointMixin
@@ -91,12 +88,7 @@ __all__ = (
@strawberry.type @strawberry.type
class ComponentType( class ComponentType(OwnerMixin, NetBoxObjectType):
ChangelogMixin,
CustomFieldsMixin,
TagsMixin,
BaseObjectType
):
""" """
Base type for device/VM components Base type for device/VM components
""" """
@@ -159,7 +151,7 @@ class CableTerminationType(NetBoxObjectType):
filters=CableFilter, filters=CableFilter,
pagination=True pagination=True
) )
class CableType(NetBoxObjectType): class CableType(PrimaryObjectType):
color: str color: str
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -236,7 +228,7 @@ class ConsoleServerPortTemplateType(ModularComponentTemplateType):
filters=DeviceFilter, filters=DeviceFilter,
pagination=True pagination=True
) )
class DeviceType(ConfigContextMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType): class DeviceType(ConfigContextMixin, ImageAttachmentsMixin, ContactsMixin, PrimaryObjectType):
console_port_count: BigInt console_port_count: BigInt
console_server_port_count: BigInt console_server_port_count: BigInt
power_port_count: BigInt power_port_count: BigInt
@@ -339,7 +331,7 @@ class InventoryItemTemplateType(ComponentTemplateType):
filters=DeviceRoleFilter, filters=DeviceRoleFilter,
pagination=True pagination=True
) )
class DeviceRoleType(OrganizationalObjectType): class DeviceRoleType(NestedGroupObjectType):
parent: Annotated['DeviceRoleType', strawberry.lazy('dcim.graphql.types')] | None parent: Annotated['DeviceRoleType', strawberry.lazy('dcim.graphql.types')] | None
children: List[Annotated['DeviceRoleType', strawberry.lazy('dcim.graphql.types')]] children: List[Annotated['DeviceRoleType', strawberry.lazy('dcim.graphql.types')]]
color: str color: str
@@ -355,7 +347,7 @@ class DeviceRoleType(OrganizationalObjectType):
filters=DeviceTypeFilter, filters=DeviceTypeFilter,
pagination=True pagination=True
) )
class DeviceTypeType(NetBoxObjectType): class DeviceTypeType(PrimaryObjectType):
console_port_template_count: BigInt console_port_template_count: BigInt
console_server_port_template_count: BigInt console_server_port_template_count: BigInt
power_port_template_count: BigInt power_port_template_count: BigInt
@@ -412,7 +404,7 @@ class FrontPortTemplateType(ModularComponentTemplateType):
filters=MACAddressFilter, filters=MACAddressFilter,
pagination=True pagination=True
) )
class MACAddressType(NetBoxObjectType): class MACAddressType(PrimaryObjectType):
mac_address: str mac_address: str
@strawberry_django.field @strawberry_django.field
@@ -512,7 +504,7 @@ class InventoryItemRoleType(OrganizationalObjectType):
filters=LocationFilter, filters=LocationFilter,
pagination=True pagination=True
) )
class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, OrganizationalObjectType): class LocationType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NestedGroupObjectType):
site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')] site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
parent: Annotated["LocationType", strawberry.lazy('dcim.graphql.types')] | None parent: Annotated["LocationType", strawberry.lazy('dcim.graphql.types')] | None
@@ -555,7 +547,7 @@ class ManufacturerType(OrganizationalObjectType, ContactsMixin):
filters=ModuleFilter, filters=ModuleFilter,
pagination=True pagination=True
) )
class ModuleType(NetBoxObjectType): class ModuleType(PrimaryObjectType):
device: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] device: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')]
module_bay: Annotated["ModuleBayType", strawberry.lazy('dcim.graphql.types')] module_bay: Annotated["ModuleBayType", strawberry.lazy('dcim.graphql.types')]
module_type: Annotated["ModuleTypeType", strawberry.lazy('dcim.graphql.types')] module_type: Annotated["ModuleTypeType", strawberry.lazy('dcim.graphql.types')]
@@ -602,7 +594,7 @@ class ModuleBayTemplateType(ModularComponentTemplateType):
filters=ModuleTypeProfileFilter, filters=ModuleTypeProfileFilter,
pagination=True pagination=True
) )
class ModuleTypeProfileType(NetBoxObjectType): class ModuleTypeProfileType(PrimaryObjectType):
module_types: List[Annotated["ModuleType", strawberry.lazy('dcim.graphql.types')]] module_types: List[Annotated["ModuleType", strawberry.lazy('dcim.graphql.types')]]
@@ -612,7 +604,7 @@ class ModuleTypeProfileType(NetBoxObjectType):
filters=ModuleTypeFilter, filters=ModuleTypeFilter,
pagination=True pagination=True
) )
class ModuleTypeType(NetBoxObjectType): class ModuleTypeType(PrimaryObjectType):
profile: Annotated["ModuleTypeProfileType", strawberry.lazy('dcim.graphql.types')] | None profile: Annotated["ModuleTypeProfileType", strawberry.lazy('dcim.graphql.types')] | None
manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')] manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')]
@@ -632,7 +624,7 @@ class ModuleTypeType(NetBoxObjectType):
filters=PlatformFilter, filters=PlatformFilter,
pagination=True pagination=True
) )
class PlatformType(OrganizationalObjectType): class PlatformType(NestedGroupObjectType):
parent: Annotated['PlatformType', strawberry.lazy('dcim.graphql.types')] | None parent: Annotated['PlatformType', strawberry.lazy('dcim.graphql.types')] | None
children: List[Annotated['PlatformType', strawberry.lazy('dcim.graphql.types')]] children: List[Annotated['PlatformType', strawberry.lazy('dcim.graphql.types')]]
manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')] | None manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')] | None
@@ -648,7 +640,7 @@ class PlatformType(OrganizationalObjectType):
filters=PowerFeedFilter, filters=PowerFeedFilter,
pagination=True pagination=True
) )
class PowerFeedType(NetBoxObjectType, CabledObjectMixin, PathEndpointMixin): class PowerFeedType(CabledObjectMixin, PathEndpointMixin, PrimaryObjectType):
power_panel: Annotated["PowerPanelType", strawberry.lazy('dcim.graphql.types')] power_panel: Annotated["PowerPanelType", strawberry.lazy('dcim.graphql.types')]
rack: Annotated["RackType", strawberry.lazy('dcim.graphql.types')] | None rack: Annotated["RackType", strawberry.lazy('dcim.graphql.types')] | None
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -682,7 +674,7 @@ class PowerOutletTemplateType(ModularComponentTemplateType):
filters=PowerPanelFilter, filters=PowerPanelFilter,
pagination=True pagination=True
) )
class PowerPanelType(NetBoxObjectType, ContactsMixin): class PowerPanelType(ContactsMixin, PrimaryObjectType):
site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')] site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]
location: Annotated["LocationType", strawberry.lazy('dcim.graphql.types')] | None location: Annotated["LocationType", strawberry.lazy('dcim.graphql.types')] | None
@@ -716,7 +708,7 @@ class PowerPortTemplateType(ModularComponentTemplateType):
filters=RackTypeFilter, filters=RackTypeFilter,
pagination=True pagination=True
) )
class RackTypeType(NetBoxObjectType): class RackTypeType(PrimaryObjectType):
manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')] manufacturer: Annotated["ManufacturerType", strawberry.lazy('dcim.graphql.types')]
@@ -726,7 +718,7 @@ class RackTypeType(NetBoxObjectType):
filters=RackFilter, filters=RackFilter,
pagination=True pagination=True
) )
class RackType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType): class RackType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, PrimaryObjectType):
site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')] site: Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]
location: Annotated["LocationType", strawberry.lazy('dcim.graphql.types')] | None location: Annotated["LocationType", strawberry.lazy('dcim.graphql.types')] | None
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -745,7 +737,7 @@ class RackType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObje
filters=RackReservationFilter, filters=RackReservationFilter,
pagination=True pagination=True
) )
class RackReservationType(NetBoxObjectType): class RackReservationType(PrimaryObjectType):
units: List[int] units: List[int]
rack: Annotated["RackType", strawberry.lazy('dcim.graphql.types')] rack: Annotated["RackType", strawberry.lazy('dcim.graphql.types')]
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -794,7 +786,7 @@ class RearPortTemplateType(ModularComponentTemplateType):
filters=RegionFilter, filters=RegionFilter,
pagination=True pagination=True
) )
class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): class RegionType(VLANGroupsMixin, ContactsMixin, NestedGroupObjectType):
sites: List[Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]] sites: List[Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]]
children: List[Annotated["RegionType", strawberry.lazy('dcim.graphql.types')]] children: List[Annotated["RegionType", strawberry.lazy('dcim.graphql.types')]]
@@ -820,7 +812,7 @@ class RegionType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType):
filters=SiteFilter, filters=SiteFilter,
pagination=True pagination=True
) )
class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObjectType): class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, PrimaryObjectType):
time_zone: str | None time_zone: str | None
region: Annotated["RegionType", strawberry.lazy('dcim.graphql.types')] | None region: Annotated["RegionType", strawberry.lazy('dcim.graphql.types')] | None
group: Annotated["SiteGroupType", strawberry.lazy('dcim.graphql.types')] | None group: Annotated["SiteGroupType", strawberry.lazy('dcim.graphql.types')] | None
@@ -855,7 +847,7 @@ class SiteType(VLANGroupsMixin, ImageAttachmentsMixin, ContactsMixin, NetBoxObje
filters=SiteGroupFilter, filters=SiteGroupFilter,
pagination=True pagination=True
) )
class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType): class SiteGroupType(VLANGroupsMixin, ContactsMixin, NestedGroupObjectType):
sites: List[Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]] sites: List[Annotated["SiteType", strawberry.lazy('dcim.graphql.types')]]
children: List[Annotated["SiteGroupType", strawberry.lazy('dcim.graphql.types')]] children: List[Annotated["SiteGroupType", strawberry.lazy('dcim.graphql.types')]]
@@ -881,7 +873,7 @@ class SiteGroupType(VLANGroupsMixin, ContactsMixin, OrganizationalObjectType):
filters=VirtualChassisFilter, filters=VirtualChassisFilter,
pagination=True pagination=True
) )
class VirtualChassisType(NetBoxObjectType): class VirtualChassisType(PrimaryObjectType):
member_count: BigInt member_count: BigInt
master: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] | None master: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] | None
@@ -894,7 +886,7 @@ class VirtualChassisType(NetBoxObjectType):
filters=VirtualDeviceContextFilter, filters=VirtualDeviceContextFilter,
pagination=True pagination=True
) )
class VirtualDeviceContextType(NetBoxObjectType): class VirtualDeviceContextType(PrimaryObjectType):
device: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] | None device: Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')] | None
primary_ip4: Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')] | None primary_ip4: Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')] | None
primary_ip6: Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')] | None primary_ip6: Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')] | None

View File

@@ -0,0 +1,243 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('dcim', '0216_poweroutlettemplate_color'),
('users', '0015_owner'),
]
operations = [
migrations.AddField(
model_name='cable',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='consoleport',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='consoleserverport',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='device',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='devicebay',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='devicerole',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='devicetype',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='frontport',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='interface',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='inventoryitem',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='inventoryitemrole',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='location',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='macaddress',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='manufacturer',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='module',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='modulebay',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='moduletype',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='moduletypeprofile',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='platform',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='powerfeed',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='poweroutlet',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='powerpanel',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='powerport',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='rack',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='rackreservation',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='rackrole',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='racktype',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='rearport',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='region',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='site',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='sitegroup',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='virtualchassis',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='virtualdevicecontext',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
]

View File

@@ -14,6 +14,7 @@ from dcim.fields import WWNField
from dcim.models.mixins import InterfaceValidationMixin from dcim.models.mixins import InterfaceValidationMixin
from netbox.choices import ColorChoices from netbox.choices import ColorChoices
from netbox.models import OrganizationalModel, NetBoxModel from netbox.models import OrganizationalModel, NetBoxModel
from netbox.models.mixins import OwnerMixin
from utilities.fields import ColorField, NaturalOrderingField from utilities.fields import ColorField, NaturalOrderingField
from utilities.mptt import TreeManager from utilities.mptt import TreeManager
from utilities.ordering import naturalize_interface from utilities.ordering import naturalize_interface
@@ -40,7 +41,7 @@ __all__ = (
) )
class ComponentModel(NetBoxModel): class ComponentModel(OwnerMixin, NetBoxModel):
""" """
An abstract model inherited by any model which has a parent Device. An abstract model inherited by any model which has a parent Device.
""" """

View File

@@ -1,11 +1,11 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django_tables2.utils import Accessor
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 django.utils.translation import gettext_lazy as _
from django_tables2.utils import Accessor
from dcim.models import Cable from dcim.models import Cable
from netbox.tables import NetBoxTable, columns from netbox.tables import PrimaryModelTable, columns
from tenancy.tables import TenancyColumnsMixin from tenancy.tables import TenancyColumnsMixin
from .template_code import CABLE_LENGTH from .template_code import CABLE_LENGTH
@@ -48,7 +48,7 @@ class CableTerminationsColumn(tables.Column):
# Cables # Cables
# #
class CableTable(TenancyColumnsMixin, NetBoxTable): class CableTable(TenancyColumnsMixin, PrimaryModelTable):
a_terminations = CableTerminationsColumn( a_terminations = CableTerminationsColumn(
cable_end='A', cable_end='A',
orderable=False, orderable=False,
@@ -117,12 +117,11 @@ class CableTable(TenancyColumnsMixin, NetBoxTable):
verbose_name=_('Color Name'), verbose_name=_('Color Name'),
orderable=False orderable=False
) )
comments = columns.MarkdownColumn()
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:cable_list' url_name='dcim:cable_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Cable model = Cable
fields = ( fields = (
'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'device_a', 'device_b', 'rack_a', 'rack_b', 'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'device_a', 'device_b', 'rack_a', 'rack_b',

View File

@@ -3,7 +3,7 @@ from django.utils.translation import gettext_lazy as _
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from dcim import models from dcim import models
from netbox.tables import NetBoxTable, columns from netbox.tables import NestedGroupModelTable, NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from .template_code import * from .template_code import *
@@ -58,15 +58,7 @@ MACADDRESS_COPY_BUTTON = """
# Device roles # Device roles
# #
class DeviceRoleTable(NetBoxTable): class DeviceRoleTable(NestedGroupModelTable):
name = columns.MPTTColumn(
verbose_name=_('Name'),
linkify=True
)
parent = tables.Column(
verbose_name=_('Parent'),
linkify=True,
)
device_count = columns.LinkedCountColumn( device_count = columns.LinkedCountColumn(
viewname='dcim:device_list', viewname='dcim:device_list',
url_params={'role_id': 'pk'}, url_params={'role_id': 'pk'},
@@ -89,7 +81,7 @@ class DeviceRoleTable(NetBoxTable):
url_name='dcim:devicerole_list' url_name='dcim:devicerole_list'
) )
class Meta(NetBoxTable.Meta): class Meta(NestedGroupModelTable.Meta):
model = models.DeviceRole model = models.DeviceRole
fields = ( fields = (
'pk', 'id', 'name', 'parent', 'device_count', 'vm_count', 'color', 'vm_role', 'config_template', 'pk', 'id', 'name', 'parent', 'device_count', 'vm_count', 'color', 'vm_role', 'config_template',
@@ -102,15 +94,7 @@ class DeviceRoleTable(NetBoxTable):
# Platforms # Platforms
# #
class PlatformTable(NetBoxTable): class PlatformTable(NestedGroupModelTable):
name = columns.MPTTColumn(
verbose_name=_('Name'),
linkify=True
)
parent = tables.Column(
verbose_name=_('Parent'),
linkify=True,
)
manufacturer = tables.Column( manufacturer = tables.Column(
verbose_name=_('Manufacturer'), verbose_name=_('Manufacturer'),
linkify=True linkify=True
@@ -133,7 +117,7 @@ class PlatformTable(NetBoxTable):
url_name='dcim:platform_list' url_name='dcim:platform_list'
) )
class Meta(NetBoxTable.Meta): class Meta(NestedGroupModelTable.Meta):
model = models.Platform model = models.Platform
fields = ( fields = (
'pk', 'id', 'name', 'parent', 'manufacturer', 'device_count', 'vm_count', 'slug', 'config_template', 'pk', 'id', 'name', 'parent', 'manufacturer', 'device_count', 'vm_count', 'slug', 'config_template',
@@ -148,7 +132,7 @@ class PlatformTable(NetBoxTable):
# Devices # Devices
# #
class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModelTable):
name = tables.TemplateColumn( name = tables.TemplateColumn(
verbose_name=_('Name'), verbose_name=_('Name'),
template_code=DEVICE_LINK, template_code=DEVICE_LINK,
@@ -249,7 +233,6 @@ class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
accessor='parent_bay', accessor='parent_bay',
linkify=True linkify=True
) )
comments = columns.MarkdownColumn()
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:device_list' url_name='dcim:device_list'
) )
@@ -284,7 +267,7 @@ class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
verbose_name=_('Inventory items') verbose_name=_('Inventory items')
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = models.Device model = models.Device
fields = ( fields = (
'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'role', 'manufacturer', 'device_type', 'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'role', 'manufacturer', 'device_type',
@@ -1050,7 +1033,7 @@ class DeviceInventoryItemTable(InventoryItemTable):
) )
class InventoryItemRoleTable(NetBoxTable): class InventoryItemRoleTable(OrganizationalModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -1067,7 +1050,7 @@ class InventoryItemRoleTable(NetBoxTable):
url_name='dcim:inventoryitemrole_list' url_name='dcim:inventoryitemrole_list'
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = models.InventoryItemRole model = models.InventoryItemRole
fields = ( fields = (
'pk', 'id', 'name', 'inventoryitem_count', 'color', 'description', 'slug', 'tags', 'actions', 'pk', 'id', 'name', 'inventoryitem_count', 'color', 'description', 'slug', 'tags', 'actions',
@@ -1079,7 +1062,7 @@ class InventoryItemRoleTable(NetBoxTable):
# Virtual chassis # Virtual chassis
# #
class VirtualChassisTable(NetBoxTable): class VirtualChassisTable(PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -1093,14 +1076,11 @@ class VirtualChassisTable(NetBoxTable):
url_params={'virtual_chassis_id': 'pk'}, url_params={'virtual_chassis_id': 'pk'},
verbose_name=_('Members') verbose_name=_('Members')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:virtualchassis_list' url_name='dcim:virtualchassis_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = models.VirtualChassis model = models.VirtualChassis
fields = ( fields = (
'pk', 'id', 'name', 'domain', 'master', 'member_count', 'description', 'comments', 'tags', 'created', 'pk', 'id', 'name', 'domain', 'master', 'member_count', 'description', 'comments', 'tags', 'created',
@@ -1109,7 +1089,7 @@ class VirtualChassisTable(NetBoxTable):
default_columns = ('pk', 'name', 'domain', 'master', 'member_count') default_columns = ('pk', 'name', 'domain', 'master', 'member_count')
class VirtualDeviceContextTable(TenancyColumnsMixin, NetBoxTable): class VirtualDeviceContextTable(TenancyColumnsMixin, PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -1140,14 +1120,11 @@ class VirtualDeviceContextTable(TenancyColumnsMixin, NetBoxTable):
url_params={'vdc_id': 'pk'}, url_params={'vdc_id': 'pk'},
verbose_name=_('Interfaces') verbose_name=_('Interfaces')
) )
comments = columns.MarkdownColumn()
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:virtualdevicecontext_list' url_name='dcim:virtualdevicecontext_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = models.VirtualDeviceContext model = models.VirtualDeviceContext
fields = ( fields = (
'pk', 'id', 'name', 'status', 'identifier', 'tenant', 'tenant_group', 'primary_ip', 'primary_ip4', 'pk', 'id', 'name', 'status', 'identifier', 'tenant', 'tenant_group', 'primary_ip', 'primary_ip4',
@@ -1158,7 +1135,7 @@ class VirtualDeviceContextTable(TenancyColumnsMixin, NetBoxTable):
) )
class MACAddressTable(NetBoxTable): class MACAddressTable(PrimaryModelTable):
mac_address = tables.TemplateColumn( mac_address = tables.TemplateColumn(
template_code=MACADDRESS_LINK, template_code=MACADDRESS_LINK,
verbose_name=_('MAC Address') verbose_name=_('MAC Address')
@@ -1181,7 +1158,7 @@ class MACAddressTable(NetBoxTable):
extra_buttons=MACADDRESS_COPY_BUTTON extra_buttons=MACADDRESS_COPY_BUTTON
) )
class Meta(DeviceComponentTable.Meta): class Meta(PrimaryModelTable.Meta):
model = models.MACAddress model = models.MACAddress
fields = ( fields = (
'pk', 'id', 'mac_address', 'assigned_object_parent', 'assigned_object', 'description', 'comments', 'tags', 'pk', 'id', 'mac_address', 'assigned_object_parent', 'assigned_object', 'description', 'comments', 'tags',

View File

@@ -2,7 +2,7 @@ import django_tables2 as tables
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from dcim import models from dcim import models
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin from tenancy.tables import ContactsColumnMixin
from .template_code import MODULAR_COMPONENT_TEMPLATE_BUTTONS, WEIGHT from .template_code import MODULAR_COMPONENT_TEMPLATE_BUTTONS, WEIGHT
@@ -26,7 +26,7 @@ __all__ = (
# Manufacturers # Manufacturers
# #
class ManufacturerTable(ContactsColumnMixin, NetBoxTable): class ManufacturerTable(ContactsColumnMixin, OrganizationalModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -60,7 +60,7 @@ class ManufacturerTable(ContactsColumnMixin, NetBoxTable):
url_name='dcim:manufacturer_list' url_name='dcim:manufacturer_list'
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = models.Manufacturer model = models.Manufacturer
fields = ( fields = (
'pk', 'id', 'name', 'racktype_count', 'devicetype_count', 'moduletype_count', 'inventoryitem_count', 'pk', 'id', 'name', 'racktype_count', 'devicetype_count', 'moduletype_count', 'inventoryitem_count',
@@ -76,7 +76,7 @@ class ManufacturerTable(ContactsColumnMixin, NetBoxTable):
# Device types # Device types
# #
class DeviceTypeTable(NetBoxTable): class DeviceTypeTable(PrimaryModelTable):
model = tables.Column( model = tables.Column(
linkify=True, linkify=True,
verbose_name=_('Device Type') verbose_name=_('Device Type')
@@ -93,9 +93,6 @@ class DeviceTypeTable(NetBoxTable):
verbose_name=_('Full Depth'), verbose_name=_('Full Depth'),
false_mark=None false_mark=None
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:devicetype_list' url_name='dcim:devicetype_list'
) )
@@ -148,7 +145,7 @@ class DeviceTypeTable(NetBoxTable):
verbose_name=_('Inventory Items') verbose_name=_('Inventory Items')
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = models.DeviceType model = models.DeviceType
fields = ( fields = (
'pk', 'id', 'model', 'manufacturer', 'default_platform', 'slug', 'part_number', 'u_height', 'pk', 'id', 'model', 'manufacturer', 'default_platform', 'slug', 'part_number', 'u_height',

View File

@@ -1,8 +1,8 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from dcim.models import Module, ModuleType, ModuleTypeProfile from dcim.models import Module, ModuleType, ModuleTypeProfile
from netbox.tables import NetBoxTable, columns from netbox.tables import PrimaryModelTable, columns
from .template_code import MODULETYPEPROFILE_ATTRIBUTES, WEIGHT from .template_code import MODULETYPEPROFILE_ATTRIBUTES, WEIGHT
__all__ = ( __all__ = (
@@ -12,7 +12,7 @@ __all__ = (
) )
class ModuleTypeProfileTable(NetBoxTable): class ModuleTypeProfileTable(PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -23,14 +23,11 @@ class ModuleTypeProfileTable(NetBoxTable):
orderable=False, orderable=False,
verbose_name=_('Attributes') verbose_name=_('Attributes')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:moduletypeprofile_list' url_name='dcim:moduletypeprofile_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = ModuleTypeProfile model = ModuleTypeProfile
fields = ( fields = (
'pk', 'id', 'name', 'description', 'comments', 'tags', 'created', 'last_updated', 'pk', 'id', 'name', 'description', 'comments', 'tags', 'created', 'last_updated',
@@ -40,7 +37,7 @@ class ModuleTypeProfileTable(NetBoxTable):
) )
class ModuleTypeTable(NetBoxTable): class ModuleTypeTable(PrimaryModelTable):
profile = tables.Column( profile = tables.Column(
verbose_name=_('Profile'), verbose_name=_('Profile'),
linkify=True linkify=True
@@ -64,14 +61,11 @@ class ModuleTypeTable(NetBoxTable):
url_params={'module_type_id': 'pk'}, url_params={'module_type_id': 'pk'},
verbose_name=_('Instances') verbose_name=_('Instances')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:moduletype_list' url_name='dcim:moduletype_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = ModuleType model = ModuleType
fields = ( fields = (
'pk', 'id', 'model', 'profile', 'manufacturer', 'part_number', 'airflow', 'weight', 'description', 'pk', 'id', 'model', 'profile', 'manufacturer', 'part_number', 'airflow', 'weight', 'description',
@@ -82,7 +76,7 @@ class ModuleTypeTable(NetBoxTable):
) )
class ModuleTable(NetBoxTable): class ModuleTable(PrimaryModelTable):
device = tables.Column( device = tables.Column(
verbose_name=_('Device'), verbose_name=_('Device'),
linkify=True linkify=True
@@ -103,14 +97,11 @@ class ModuleTable(NetBoxTable):
status = columns.ChoiceFieldColumn( status = columns.ChoiceFieldColumn(
verbose_name=_('Status'), verbose_name=_('Status'),
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:module_list' url_name='dcim:module_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Module model = Module
fields = ( fields = (
'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'status', 'serial', 'asset_tag', 'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'status', 'serial', 'asset_tag',

View File

@@ -1,10 +1,9 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from dcim.models import PowerFeed, PowerPanel from dcim.models import PowerFeed, PowerPanel
from netbox.tables import PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from netbox.tables import NetBoxTable, columns
from .devices import CableTerminationTable from .devices import CableTerminationTable
__all__ = ( __all__ = (
@@ -17,7 +16,7 @@ __all__ = (
# Power panels # Power panels
# #
class PowerPanelTable(ContactsColumnMixin, NetBoxTable): class PowerPanelTable(ContactsColumnMixin, PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -35,14 +34,11 @@ class PowerPanelTable(ContactsColumnMixin, NetBoxTable):
url_params={'power_panel_id': 'pk'}, url_params={'power_panel_id': 'pk'},
verbose_name=_('Power Feeds') verbose_name=_('Power Feeds')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:powerpanel_list' url_name='dcim:powerpanel_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = PowerPanel model = PowerPanel
fields = ( fields = (
'pk', 'id', 'name', 'site', 'location', 'powerfeed_count', 'contacts', 'description', 'comments', 'tags', 'pk', 'id', 'name', 'site', 'location', 'powerfeed_count', 'contacts', 'description', 'comments', 'tags',
@@ -57,7 +53,7 @@ class PowerPanelTable(ContactsColumnMixin, NetBoxTable):
# We're not using PathEndpointTable for PowerFeed because power connections # We're not using PathEndpointTable for PowerFeed because power connections
# cannot traverse pass-through ports. # cannot traverse pass-through ports.
class PowerFeedTable(TenancyColumnsMixin, CableTerminationTable): class PowerFeedTable(TenancyColumnsMixin, CableTerminationTable, PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -92,14 +88,11 @@ class PowerFeedTable(TenancyColumnsMixin, CableTerminationTable):
linkify=True, linkify=True,
verbose_name=_('Site'), verbose_name=_('Site'),
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:powerfeed_list' url_name='dcim:powerfeed_list'
) )
class Meta(NetBoxTable.Meta): class Meta(CableTerminationTable.Meta, PrimaryModelTable.Meta):
model = PowerFeed model = PowerFeed
fields = ( fields = (
'pk', 'id', 'name', 'power_panel', 'site', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'pk', 'id', 'name', 'power_panel', 'site', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage',

View File

@@ -1,9 +1,9 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from dcim.models import Rack, RackReservation, RackRole, RackType from dcim.models import Rack, RackReservation, RackRole, RackType
from netbox.tables import NetBoxTable, columns from netbox.tables import OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from .template_code import OUTER_UNIT, WEIGHT from .template_code import OUTER_UNIT, WEIGHT
@@ -15,11 +15,7 @@ __all__ = (
) )
# class RackRoleTable(OrganizationalModelTable):
# Rack roles
#
class RackRoleTable(NetBoxTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -36,7 +32,7 @@ class RackRoleTable(NetBoxTable):
url_name='dcim:rackrole_list' url_name='dcim:rackrole_list'
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = RackRole model = RackRole
fields = ( fields = (
'pk', 'id', 'name', 'rack_count', 'color', 'description', 'slug', 'tags', 'actions', 'created', 'pk', 'id', 'name', 'rack_count', 'color', 'description', 'slug', 'tags', 'actions', 'created',
@@ -45,11 +41,7 @@ class RackRoleTable(NetBoxTable):
default_columns = ('pk', 'name', 'rack_count', 'color', 'description') default_columns = ('pk', 'name', 'rack_count', 'color', 'description')
# class RackTypeTable(PrimaryModelTable):
# Rack Types
#
class RackTypeTable(NetBoxTable):
model = tables.Column( model = tables.Column(
verbose_name=_('Model'), verbose_name=_('Model'),
linkify=True linkify=True
@@ -84,9 +76,6 @@ class RackTypeTable(NetBoxTable):
template_code=WEIGHT, template_code=WEIGHT,
order_by=('_abs_max_weight', 'weight_unit') order_by=('_abs_max_weight', 'weight_unit')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
instance_count = columns.LinkedCountColumn( instance_count = columns.LinkedCountColumn(
viewname='dcim:rack_list', viewname='dcim:rack_list',
url_params={'rack_type_id': 'pk'}, url_params={'rack_type_id': 'pk'},
@@ -96,7 +85,7 @@ class RackTypeTable(NetBoxTable):
url_name='dcim:rack_list' url_name='dcim:rack_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = RackType model = RackType
fields = ( fields = (
'pk', 'id', 'model', 'manufacturer', 'form_factor', 'u_height', 'starting_unit', 'width', 'outer_width', 'pk', 'id', 'model', 'manufacturer', 'form_factor', 'u_height', 'starting_unit', 'width', 'outer_width',
@@ -108,11 +97,7 @@ class RackTypeTable(NetBoxTable):
) )
# class RackTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModelTable):
# Racks
#
class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -144,9 +129,6 @@ class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
template_code="{{ value }}U", template_code="{{ value }}U",
verbose_name=_('Height') verbose_name=_('Height')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
device_count = columns.LinkedCountColumn( device_count = columns.LinkedCountColumn(
viewname='dcim:device_list', viewname='dcim:device_list',
url_params={'rack_id': 'pk'}, url_params={'rack_id': 'pk'},
@@ -186,7 +168,7 @@ class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
order_by=('_abs_max_weight', 'weight_unit') order_by=('_abs_max_weight', 'weight_unit')
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Rack model = Rack
fields = ( fields = (
'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role', 'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role',
@@ -201,11 +183,7 @@ class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
) )
# class RackReservationTable(TenancyColumnsMixin, PrimaryModelTable):
# Rack reservations
#
class RackReservationTable(TenancyColumnsMixin, NetBoxTable):
reservation = tables.Column( reservation = tables.Column(
verbose_name=_('Reservation'), verbose_name=_('Reservation'),
accessor='pk', accessor='pk',
@@ -232,14 +210,11 @@ class RackReservationTable(TenancyColumnsMixin, NetBoxTable):
status = columns.ChoiceFieldColumn( status = columns.ChoiceFieldColumn(
verbose_name=_('Status'), verbose_name=_('Status'),
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:rackreservation_list' url_name='dcim:rackreservation_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = RackReservation model = RackReservation
fields = ( fields = (
'pk', 'id', 'reservation', 'site', 'location', 'rack', 'unit_list', 'status', 'user', 'created', 'tenant', 'pk', 'id', 'reservation', 'site', 'location', 'rack', 'unit_list', 'status', 'user', 'created', 'tenant',

View File

@@ -1,10 +1,9 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from dcim.models import Location, Region, Site, SiteGroup from dcim.models import Location, Region, Site, SiteGroup
from netbox.tables import NestedGroupModelTable, PrimaryModelTable, columns
from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin
from netbox.tables import NetBoxTable, columns
from .template_code import LOCATION_BUTTONS from .template_code import LOCATION_BUTTONS
__all__ = ( __all__ = (
@@ -15,19 +14,7 @@ __all__ = (
) )
# class RegionTable(ContactsColumnMixin, NestedGroupModelTable):
# Regions
#
class RegionTable(ContactsColumnMixin, NetBoxTable):
name = columns.MPTTColumn(
verbose_name=_('Name'),
linkify=True
)
parent = tables.Column(
verbose_name=_('Parent'),
linkify=True,
)
site_count = columns.LinkedCountColumn( site_count = columns.LinkedCountColumn(
viewname='dcim:site_list', viewname='dcim:site_list',
url_params={'region_id': 'pk'}, url_params={'region_id': 'pk'},
@@ -36,11 +23,8 @@ class RegionTable(ContactsColumnMixin, NetBoxTable):
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:region_list' url_name='dcim:region_list'
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
class Meta(NetBoxTable.Meta): class Meta(NestedGroupModelTable.Meta):
model = Region model = Region
fields = ( fields = (
'pk', 'id', 'name', 'parent', 'slug', 'site_count', 'description', 'comments', 'contacts', 'tags', 'pk', 'id', 'name', 'parent', 'slug', 'site_count', 'description', 'comments', 'contacts', 'tags',
@@ -49,19 +33,7 @@ class RegionTable(ContactsColumnMixin, NetBoxTable):
default_columns = ('pk', 'name', 'site_count', 'description') default_columns = ('pk', 'name', 'site_count', 'description')
# class SiteGroupTable(ContactsColumnMixin, NestedGroupModelTable):
# Site groups
#
class SiteGroupTable(ContactsColumnMixin, NetBoxTable):
name = columns.MPTTColumn(
verbose_name=_('Name'),
linkify=True
)
parent = tables.Column(
verbose_name=_('Parent'),
linkify=True,
)
site_count = columns.LinkedCountColumn( site_count = columns.LinkedCountColumn(
viewname='dcim:site_list', viewname='dcim:site_list',
url_params={'group_id': 'pk'}, url_params={'group_id': 'pk'},
@@ -70,11 +42,8 @@ class SiteGroupTable(ContactsColumnMixin, NetBoxTable):
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:sitegroup_list' url_name='dcim:sitegroup_list'
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
class Meta(NetBoxTable.Meta): class Meta(NestedGroupModelTable.Meta):
model = SiteGroup model = SiteGroup
fields = ( fields = (
'pk', 'id', 'name', 'parent', 'slug', 'site_count', 'description', 'comments', 'contacts', 'tags', 'pk', 'id', 'name', 'parent', 'slug', 'site_count', 'description', 'comments', 'contacts', 'tags',
@@ -83,11 +52,7 @@ class SiteGroupTable(ContactsColumnMixin, NetBoxTable):
default_columns = ('pk', 'name', 'site_count', 'description') default_columns = ('pk', 'name', 'site_count', 'description')
# class SiteTable(TenancyColumnsMixin, ContactsColumnMixin, PrimaryModelTable):
# Sites
#
class SiteTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -117,14 +82,11 @@ class SiteTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
url_params={'site_id': 'pk'}, url_params={'site_id': 'pk'},
verbose_name=_('Devices') verbose_name=_('Devices')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='dcim:site_list' url_name='dcim:site_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Site model = Site
fields = ( fields = (
'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'tenant_group', 'asns', 'pk', 'id', 'name', 'slug', 'status', 'facility', 'region', 'group', 'tenant', 'tenant_group', 'asns',
@@ -134,19 +96,7 @@ class SiteTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
default_columns = ('pk', 'name', 'status', 'facility', 'region', 'group', 'tenant', 'description') default_columns = ('pk', 'name', 'status', 'facility', 'region', 'group', 'tenant', 'description')
# class LocationTable(TenancyColumnsMixin, ContactsColumnMixin, NestedGroupModelTable):
# Locations
#
class LocationTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
name = columns.MPTTColumn(
verbose_name=_('Name'),
linkify=True
)
parent = tables.Column(
verbose_name=_('Parent'),
linkify=True,
)
site = tables.Column( site = tables.Column(
verbose_name=_('Site'), verbose_name=_('Site'),
linkify=True linkify=True
@@ -175,11 +125,8 @@ class LocationTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable):
actions = columns.ActionsColumn( actions = columns.ActionsColumn(
extra_buttons=LOCATION_BUTTONS extra_buttons=LOCATION_BUTTONS
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
class Meta(NetBoxTable.Meta): class Meta(NestedGroupModelTable.Meta):
model = Location model = Location
fields = ( fields = (
'pk', 'id', 'name', 'parent', 'site', 'status', 'facility', 'tenant', 'tenant_group', 'rack_count', 'pk', 'id', 'name', 'parent', 'site', 'status', 'facility', 'tenant', 'tenant_group', 'rack_count',

View File

@@ -8,7 +8,8 @@ from dcim.api.serializers_.sites import LocationSerializer, RegionSerializer, Si
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
from extras.models import ConfigContext, ConfigContextProfile, Tag from extras.models import ConfigContext, ConfigContextProfile, Tag
from netbox.api.fields import SerializedPKRelatedField from netbox.api.fields import SerializedPKRelatedField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer from netbox.api.serializers import ChangeLogMessageSerializer, PrimaryModelSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
from tenancy.api.serializers_.tenants import TenantSerializer, TenantGroupSerializer from tenancy.api.serializers_.tenants import TenantSerializer, TenantGroupSerializer
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from virtualization.api.serializers_.clusters import ClusterSerializer, ClusterGroupSerializer, ClusterTypeSerializer from virtualization.api.serializers_.clusters import ClusterSerializer, ClusterGroupSerializer, ClusterTypeSerializer
@@ -20,13 +21,7 @@ __all__ = (
) )
class ConfigContextProfileSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): class ConfigContextProfileSerializer(PrimaryModelSerializer):
tags = serializers.SlugRelatedField(
queryset=Tag.objects.all(),
slug_field='slug',
required=False,
many=True
)
data_source = DataSourceSerializer( data_source = DataSourceSerializer(
nested=True, nested=True,
required=False required=False
@@ -39,13 +34,13 @@ class ConfigContextProfileSerializer(ChangeLogMessageSerializer, ValidatedModelS
class Meta: class Meta:
model = ConfigContextProfile model = ConfigContextProfile
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'schema', 'tags', 'comments', 'data_source', 'id', 'url', 'display_url', 'display', 'name', 'description', 'schema', 'tags', 'owner', 'comments',
'data_path', 'data_file', 'data_synced', 'created', 'last_updated', 'data_source', 'data_path', 'data_file', 'data_synced', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')
class ConfigContextSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): class ConfigContextSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
profile = ConfigContextProfileSerializer( profile = ConfigContextProfileSerializer(
nested=True, nested=True,
required=False, required=False,
@@ -156,7 +151,7 @@ class ConfigContextSerializer(ChangeLogMessageSerializer, ValidatedModelSerializ
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'weight', 'profile', 'description', 'is_active', 'regions', 'id', 'url', 'display_url', 'display', 'name', 'weight', 'profile', 'description', 'is_active', 'regions',
'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types', 'site_groups', 'sites', 'locations', 'device_types', 'roles', 'platforms', 'cluster_types',
'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'tags', 'data_source', 'data_path', 'data_file', 'cluster_groups', 'clusters', 'tenant_groups', 'tenants', 'owner', 'tags', 'data_source', 'data_path',
'data_synced', 'data', 'created', 'last_updated', 'data_file', 'data_synced', 'data', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')

View File

@@ -2,13 +2,19 @@ from core.api.serializers_.data import DataFileSerializer, DataSourceSerializer
from extras.models import ConfigTemplate from extras.models import ConfigTemplate
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from netbox.api.serializers.features import TaggableModelSerializer from netbox.api.serializers.features import TaggableModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = ( __all__ = (
'ConfigTemplateSerializer', 'ConfigTemplateSerializer',
) )
class ConfigTemplateSerializer(ChangeLogMessageSerializer, TaggableModelSerializer, ValidatedModelSerializer): class ConfigTemplateSerializer(
OwnerMixin,
ChangeLogMessageSerializer,
TaggableModelSerializer,
ValidatedModelSerializer
):
data_source = DataSourceSerializer( data_source = DataSourceSerializer(
nested=True, nested=True,
required=False required=False
@@ -23,6 +29,6 @@ class ConfigTemplateSerializer(ChangeLogMessageSerializer, TaggableModelSerializ
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'environment_params', 'template_code', 'id', 'url', 'display_url', 'display', 'name', 'description', 'environment_params', 'template_code',
'mime_type', 'file_name', 'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file', 'mime_type', 'file_name', 'file_extension', 'as_attachment', 'data_source', 'data_path', 'data_file',
'data_synced', 'tags', 'created', 'last_updated', 'data_synced', 'owner', 'tags', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')

View File

@@ -8,6 +8,7 @@ from extras.choices import *
from extras.models import CustomField, CustomFieldChoiceSet from extras.models import CustomField, CustomFieldChoiceSet
from netbox.api.fields import ChoiceField, ContentTypeField from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = ( __all__ = (
'CustomFieldChoiceSetSerializer', 'CustomFieldChoiceSetSerializer',
@@ -15,7 +16,7 @@ __all__ = (
) )
class CustomFieldChoiceSetSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): class CustomFieldChoiceSetSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
base_choices = ChoiceField( base_choices = ChoiceField(
choices=CustomFieldChoiceSetBaseChoices, choices=CustomFieldChoiceSetBaseChoices,
required=False required=False
@@ -32,12 +33,12 @@ class CustomFieldChoiceSetSerializer(ChangeLogMessageSerializer, ValidatedModelS
model = CustomFieldChoiceSet model = CustomFieldChoiceSet
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'base_choices', 'extra_choices', 'id', 'url', 'display_url', 'display', 'name', 'description', 'base_choices', 'extra_choices',
'order_alphabetically', 'choices_count', 'created', 'last_updated', 'order_alphabetically', 'choices_count', 'owner', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description', 'choices_count') brief_fields = ('id', 'url', 'display', 'name', 'description', 'choices_count')
class CustomFieldSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): class CustomFieldSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField( object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('custom_fields'), queryset=ObjectType.objects.with_feature('custom_fields'),
many=True many=True
@@ -64,8 +65,8 @@ class CustomFieldSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer
'id', 'url', 'display_url', 'display', 'object_types', 'type', 'related_object_type', 'data_type', 'id', 'url', 'display_url', 'display', 'object_types', 'type', 'related_object_type', 'data_type',
'name', 'label', 'group_name', 'description', 'required', 'unique', 'search_weight', 'filter_logic', 'name', 'label', 'group_name', 'description', 'required', 'unique', 'search_weight', 'filter_logic',
'ui_visible', 'ui_editable', 'is_cloneable', 'default', 'related_object_filter', 'weight', 'ui_visible', 'ui_editable', 'is_cloneable', 'default', 'related_object_filter', 'weight',
'validation_minimum', 'validation_maximum', 'validation_regex', 'choice_set', 'comments', 'created', 'validation_minimum', 'validation_maximum', 'validation_regex', 'choice_set', 'owner', 'comments',
'last_updated', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')

View File

@@ -2,13 +2,14 @@ from core.models import ObjectType
from extras.models import CustomLink from extras.models import CustomLink
from netbox.api.fields import ContentTypeField from netbox.api.fields import ContentTypeField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = ( __all__ = (
'CustomLinkSerializer', 'CustomLinkSerializer',
) )
class CustomLinkSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): class CustomLinkSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField( object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('custom_links'), queryset=ObjectType.objects.with_feature('custom_links'),
many=True many=True
@@ -18,6 +19,6 @@ class CustomLinkSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer)
model = CustomLink model = CustomLink
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'name', 'enabled', 'link_text', 'link_url', 'id', 'url', 'display_url', 'display', 'object_types', 'name', 'enabled', 'link_text', 'link_url',
'weight', 'group_name', 'button_class', 'new_window', 'created', 'last_updated', 'weight', 'group_name', 'button_class', 'new_window', 'owner', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name') brief_fields = ('id', 'url', 'display', 'name')

View File

@@ -7,6 +7,7 @@ from extras.choices import *
from extras.models import EventRule, Webhook from extras.models import EventRule, Webhook
from netbox.api.fields import ChoiceField, ContentTypeField from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer
from users.api.serializers_.mixins import OwnerMixin
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from .scripts import ScriptSerializer from .scripts import ScriptSerializer
@@ -20,7 +21,7 @@ __all__ = (
# Event Rules # Event Rules
# #
class EventRuleSerializer(NetBoxModelSerializer): class EventRuleSerializer(OwnerMixin, NetBoxModelSerializer):
object_types = ContentTypeField( object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('event_rules'), queryset=ObjectType.objects.with_feature('event_rules'),
many=True many=True
@@ -36,7 +37,7 @@ class EventRuleSerializer(NetBoxModelSerializer):
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'name', 'enabled', 'event_types', 'conditions', 'id', 'url', 'display_url', 'display', 'object_types', 'name', 'enabled', 'event_types', 'conditions',
'action_type', 'action_object_type', 'action_object_id', 'action_object', 'description', 'custom_fields', 'action_type', 'action_object_type', 'action_object_id', 'action_object', 'description', 'custom_fields',
'tags', 'created', 'last_updated', 'owner', 'tags', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')
@@ -56,13 +57,13 @@ class EventRuleSerializer(NetBoxModelSerializer):
# Webhooks # Webhooks
# #
class WebhookSerializer(NetBoxModelSerializer): class WebhookSerializer(OwnerMixin, NetBoxModelSerializer):
class Meta: class Meta:
model = Webhook model = Webhook
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'description', 'payload_url', 'http_method', 'id', 'url', 'display_url', 'display', 'name', 'description', 'payload_url', 'http_method',
'http_content_type', 'additional_headers', 'body_template', 'secret', 'ssl_verification', 'ca_file_path', 'http_content_type', 'additional_headers', 'body_template', 'secret', 'ssl_verification', 'ca_file_path',
'custom_fields', 'tags', 'created', 'last_updated', 'custom_fields', 'owner', 'tags', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')

View File

@@ -3,13 +3,14 @@ from core.models import ObjectType
from extras.models import ExportTemplate from extras.models import ExportTemplate
from netbox.api.fields import ContentTypeField from netbox.api.fields import ContentTypeField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = ( __all__ = (
'ExportTemplateSerializer', 'ExportTemplateSerializer',
) )
class ExportTemplateSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): class ExportTemplateSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField( object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('export_templates'), queryset=ObjectType.objects.with_feature('export_templates'),
many=True many=True
@@ -28,6 +29,6 @@ class ExportTemplateSerializer(ChangeLogMessageSerializer, ValidatedModelSeriali
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'name', 'description', 'environment_params', 'id', 'url', 'display_url', 'display', 'object_types', 'name', 'description', 'environment_params',
'template_code', 'mime_type', 'file_name', 'file_extension', 'as_attachment', 'data_source', 'template_code', 'mime_type', 'file_name', 'file_extension', 'as_attachment', 'data_source',
'data_path', 'data_file', 'data_synced', 'created', 'last_updated', 'data_path', 'data_file', 'data_synced', 'owner', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')

View File

@@ -2,13 +2,14 @@ from core.models import ObjectType
from extras.models import SavedFilter from extras.models import SavedFilter
from netbox.api.fields import ContentTypeField from netbox.api.fields import ContentTypeField
from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer from netbox.api.serializers import ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = ( __all__ = (
'SavedFilterSerializer', 'SavedFilterSerializer',
) )
class SavedFilterSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): class SavedFilterSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField( object_types = ContentTypeField(
queryset=ObjectType.objects.all(), queryset=ObjectType.objects.all(),
many=True many=True
@@ -18,6 +19,6 @@ class SavedFilterSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer
model = SavedFilter model = SavedFilter
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'object_types', 'name', 'slug', 'description', 'user', 'weight', 'id', 'url', 'display_url', 'display', 'object_types', 'name', 'slug', 'description', 'user', 'weight',
'enabled', 'shared', 'parameters', 'created', 'last_updated', 'enabled', 'shared', 'parameters', 'owner', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description')

View File

@@ -6,6 +6,7 @@ from extras.models import Tag, TaggedItem
from netbox.api.exceptions import SerializerNotFound from netbox.api.exceptions import SerializerNotFound
from netbox.api.fields import ContentTypeField, RelatedObjectCountField from netbox.api.fields import ContentTypeField, RelatedObjectCountField
from netbox.api.serializers import BaseModelSerializer, ChangeLogMessageSerializer, ValidatedModelSerializer from netbox.api.serializers import BaseModelSerializer, ChangeLogMessageSerializer, ValidatedModelSerializer
from users.api.serializers_.mixins import OwnerMixin
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
__all__ = ( __all__ = (
@@ -14,7 +15,7 @@ __all__ = (
) )
class TagSerializer(ChangeLogMessageSerializer, ValidatedModelSerializer): class TagSerializer(OwnerMixin, ChangeLogMessageSerializer, ValidatedModelSerializer):
object_types = ContentTypeField( object_types = ContentTypeField(
queryset=ObjectType.objects.with_feature('tags'), queryset=ObjectType.objects.with_feature('tags'),
many=True, many=True,

View File

@@ -5,8 +5,9 @@ from django.utils.translation import gettext as _
from core.models import DataSource, ObjectType from core.models import DataSource, ObjectType
from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site, SiteGroup
from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet from netbox.filtersets import BaseFilterSet, ChangeLoggedModelFilterSet, NetBoxModelFilterSet, PrimaryModelFilterSet
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from users.filterset_mixins import OwnerFilterMixin
from users.models import Group, User from users.models import Group, User
from utilities.filters import ( from utilities.filters import (
ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter ContentTypeFilter, MultiValueCharFilter, MultiValueNumberFilter
@@ -61,7 +62,7 @@ class ScriptFilterSet(BaseFilterSet):
) )
class WebhookFilterSet(NetBoxModelFilterSet): class WebhookFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -90,7 +91,7 @@ class WebhookFilterSet(NetBoxModelFilterSet):
) )
class EventRuleFilterSet(NetBoxModelFilterSet): class EventRuleFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -130,7 +131,7 @@ class EventRuleFilterSet(NetBoxModelFilterSet):
return queryset.filter(event_types__overlap=value) return queryset.filter(event_types__overlap=value)
class CustomFieldFilterSet(ChangeLoggedModelFilterSet): class CustomFieldFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -179,7 +180,7 @@ class CustomFieldFilterSet(ChangeLoggedModelFilterSet):
) )
class CustomFieldChoiceSetFilterSet(ChangeLoggedModelFilterSet): class CustomFieldChoiceSetFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -207,7 +208,7 @@ class CustomFieldChoiceSetFilterSet(ChangeLoggedModelFilterSet):
return queryset.filter(extra_choices__overlap=value) return queryset.filter(extra_choices__overlap=value)
class CustomLinkFilterSet(ChangeLoggedModelFilterSet): class CustomLinkFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -237,7 +238,7 @@ class CustomLinkFilterSet(ChangeLoggedModelFilterSet):
) )
class ExportTemplateFilterSet(ChangeLoggedModelFilterSet): class ExportTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -275,7 +276,7 @@ class ExportTemplateFilterSet(ChangeLoggedModelFilterSet):
) )
class SavedFilterFilterSet(ChangeLoggedModelFilterSet): class SavedFilterFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -494,7 +495,7 @@ class JournalEntryFilterSet(NetBoxModelFilterSet):
return queryset.filter(comments__icontains=value) return queryset.filter(comments__icontains=value)
class TagFilterSet(ChangeLoggedModelFilterSet): class TagFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -589,7 +590,7 @@ class TaggedItemFilterSet(BaseFilterSet):
) )
class ConfigContextProfileFilterSet(NetBoxModelFilterSet): class ConfigContextProfileFilterSet(PrimaryModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -619,7 +620,7 @@ class ConfigContextProfileFilterSet(NetBoxModelFilterSet):
) )
class ConfigContextFilterSet(ChangeLoggedModelFilterSet): class ConfigContextFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),
@@ -788,7 +789,7 @@ class ConfigContextFilterSet(ChangeLoggedModelFilterSet):
) )
class ConfigTemplateFilterSet(ChangeLoggedModelFilterSet): class ConfigTemplateFilterSet(OwnerFilterMixin, ChangeLoggedModelFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label=_('Search'), label=_('Search'),

View File

@@ -4,8 +4,8 @@ from django.utils.translation import gettext_lazy as _
from extras.choices import * from extras.choices import *
from extras.models import * from extras.models import *
from netbox.events import get_event_type_choices from netbox.events import get_event_type_choices
from netbox.forms import NetBoxModelBulkEditForm from netbox.forms import NetBoxModelBulkEditForm, PrimaryModelBulkEditForm
from netbox.forms.mixins import ChangelogMessageMixin from netbox.forms.mixins import ChangelogMessageMixin, OwnerMixin
from utilities.forms import BulkEditForm, add_blank_choice from utilities.forms import BulkEditForm, add_blank_choice
from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField from utilities.forms.fields import ColorField, CommentField, DynamicModelChoiceField
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
@@ -30,7 +30,7 @@ __all__ = (
) )
class CustomFieldBulkEditForm(ChangelogMessageMixin, BulkEditForm): class CustomFieldBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=CustomField.objects.all(), queryset=CustomField.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
@@ -98,7 +98,7 @@ class CustomFieldBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('group_name', 'description', 'choice_set') nullable_fields = ('group_name', 'description', 'choice_set')
class CustomFieldChoiceSetBulkEditForm(ChangelogMessageMixin, BulkEditForm): class CustomFieldChoiceSetBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=CustomFieldChoiceSet.objects.all(), queryset=CustomFieldChoiceSet.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
@@ -118,7 +118,7 @@ class CustomFieldChoiceSetBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('base_choices', 'description') nullable_fields = ('base_choices', 'description')
class CustomLinkBulkEditForm(ChangelogMessageMixin, BulkEditForm): class CustomLinkBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=CustomLink.objects.all(), queryset=CustomLink.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
@@ -144,7 +144,7 @@ class CustomLinkBulkEditForm(ChangelogMessageMixin, BulkEditForm):
) )
class ExportTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm): class ExportTemplateBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=ExportTemplate.objects.all(), queryset=ExportTemplate.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
@@ -177,7 +177,7 @@ class ExportTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension') nullable_fields = ('description', 'mime_type', 'file_name', 'file_extension')
class SavedFilterBulkEditForm(ChangelogMessageMixin, BulkEditForm): class SavedFilterBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=SavedFilter.objects.all(), queryset=SavedFilter.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
@@ -233,7 +233,7 @@ class TableConfigBulkEditForm(BulkEditForm):
nullable_fields = ('description',) nullable_fields = ('description',)
class WebhookBulkEditForm(NetBoxModelBulkEditForm): class WebhookBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
model = Webhook model = Webhook
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
@@ -271,7 +271,7 @@ class WebhookBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('secret', 'ca_file_path') nullable_fields = ('secret', 'ca_file_path')
class EventRuleBulkEditForm(NetBoxModelBulkEditForm): class EventRuleBulkEditForm(OwnerMixin, NetBoxModelBulkEditForm):
model = EventRule model = EventRule
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
@@ -297,7 +297,7 @@ class EventRuleBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('description', 'conditions') nullable_fields = ('description', 'conditions')
class TagBulkEditForm(ChangelogMessageMixin, BulkEditForm): class TagBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=Tag.objects.all(), queryset=Tag.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
@@ -319,17 +319,11 @@ class TagBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('description',) nullable_fields = ('description',)
class ConfigContextProfileBulkEditForm(NetBoxModelBulkEditForm): class ConfigContextProfileBulkEditForm(PrimaryModelBulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=ConfigContextProfile.objects.all(), queryset=ConfigContextProfile.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
) )
description = forms.CharField(
label=_('Description'),
required=False,
max_length=100
)
comments = CommentField()
model = ConfigContextProfile model = ConfigContextProfile
fieldsets = ( fieldsets = (
@@ -338,7 +332,7 @@ class ConfigContextProfileBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('description',) nullable_fields = ('description',)
class ConfigContextBulkEditForm(ChangelogMessageMixin, BulkEditForm): class ConfigContextBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=ConfigContext.objects.all(), queryset=ConfigContext.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput
@@ -369,7 +363,7 @@ class ConfigContextBulkEditForm(ChangelogMessageMixin, BulkEditForm):
nullable_fields = ('profile', 'description') nullable_fields = ('profile', 'description')
class ConfigTemplateBulkEditForm(ChangelogMessageMixin, BulkEditForm): class ConfigTemplateBulkEditForm(ChangelogMessageMixin, OwnerMixin, BulkEditForm):
pk = forms.ModelMultipleChoiceField( pk = forms.ModelMultipleChoiceField(
queryset=ConfigTemplate.objects.all(), queryset=ConfigTemplate.objects.all(),
widget=forms.MultipleHiddenInput widget=forms.MultipleHiddenInput

View File

@@ -9,7 +9,7 @@ from core.models import ObjectType
from extras.choices import * from extras.choices import *
from extras.models import * from extras.models import *
from netbox.events import get_event_type_choices from netbox.events import get_event_type_choices
from netbox.forms import NetBoxModelImportForm from netbox.forms import NetBoxModelImportForm, OwnerCSVMixin, PrimaryModelImportForm
from users.models import Group, User from users.models import Group, User
from utilities.forms import CSVModelForm from utilities.forms import CSVModelForm
from utilities.forms.fields import ( from utilities.forms.fields import (
@@ -33,7 +33,7 @@ __all__ = (
) )
class CustomFieldImportForm(CSVModelForm): class CustomFieldImportForm(OwnerCSVMixin, CSVModelForm):
object_types = CSVMultipleContentTypeField( object_types = CSVMultipleContentTypeField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_fields'), queryset=ObjectType.objects.with_feature('custom_fields'),
@@ -75,11 +75,11 @@ class CustomFieldImportForm(CSVModelForm):
fields = ( fields = (
'name', 'label', 'group_name', 'type', 'object_types', 'related_object_type', 'required', 'unique', 'name', 'label', 'group_name', 'type', 'object_types', 'related_object_type', 'required', 'unique',
'description', 'search_weight', 'filter_logic', 'default', 'choice_set', 'weight', 'validation_minimum', 'description', 'search_weight', 'filter_logic', 'default', 'choice_set', 'weight', 'validation_minimum',
'validation_maximum', 'validation_regex', 'ui_visible', 'ui_editable', 'is_cloneable', 'comments', 'validation_maximum', 'validation_regex', 'ui_visible', 'ui_editable', 'is_cloneable', 'owner', 'comments',
) )
class CustomFieldChoiceSetImportForm(CSVModelForm): class CustomFieldChoiceSetImportForm(OwnerCSVMixin, CSVModelForm):
base_choices = CSVChoiceField( base_choices = CSVChoiceField(
choices=CustomFieldChoiceSetBaseChoices, choices=CustomFieldChoiceSetBaseChoices,
required=False, required=False,
@@ -97,7 +97,7 @@ class CustomFieldChoiceSetImportForm(CSVModelForm):
class Meta: class Meta:
model = CustomFieldChoiceSet model = CustomFieldChoiceSet
fields = ( fields = (
'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'owner',
) )
def clean_extra_choices(self): def clean_extra_choices(self):
@@ -114,7 +114,7 @@ class CustomFieldChoiceSetImportForm(CSVModelForm):
return data return data
class CustomLinkImportForm(CSVModelForm): class CustomLinkImportForm(OwnerCSVMixin, CSVModelForm):
object_types = CSVMultipleContentTypeField( object_types = CSVMultipleContentTypeField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_links'), queryset=ObjectType.objects.with_feature('custom_links'),
@@ -131,11 +131,11 @@ class CustomLinkImportForm(CSVModelForm):
model = CustomLink model = CustomLink
fields = ( fields = (
'name', 'object_types', 'enabled', 'weight', 'group_name', 'button_class', 'new_window', 'link_text', 'name', 'object_types', 'enabled', 'weight', 'group_name', 'button_class', 'new_window', 'link_text',
'link_url', 'link_url', 'owner',
) )
class ExportTemplateImportForm(CSVModelForm): class ExportTemplateImportForm(OwnerCSVMixin, CSVModelForm):
object_types = CSVMultipleContentTypeField( object_types = CSVMultipleContentTypeField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('export_templates'), queryset=ObjectType.objects.with_feature('export_templates'),
@@ -146,30 +146,30 @@ class ExportTemplateImportForm(CSVModelForm):
model = ExportTemplate model = ExportTemplate
fields = ( fields = (
'name', 'object_types', 'description', 'environment_params', 'mime_type', 'file_name', 'file_extension', 'name', 'object_types', 'description', 'environment_params', 'mime_type', 'file_name', 'file_extension',
'as_attachment', 'template_code', 'as_attachment', 'template_code', 'owner',
) )
class ConfigContextProfileImportForm(NetBoxModelImportForm): class ConfigContextProfileImportForm(PrimaryModelImportForm):
class Meta: class Meta:
model = ConfigContextProfile model = ConfigContextProfile
fields = [ fields = [
'name', 'description', 'schema', 'comments', 'tags', 'name', 'description', 'schema', 'owner', 'comments', 'tags',
] ]
class ConfigTemplateImportForm(CSVModelForm): class ConfigTemplateImportForm(OwnerCSVMixin, CSVModelForm):
class Meta: class Meta:
model = ConfigTemplate model = ConfigTemplate
fields = ( fields = (
'name', 'description', 'template_code', 'environment_params', 'mime_type', 'file_name', 'file_extension', 'name', 'description', 'template_code', 'environment_params', 'mime_type', 'file_name', 'file_extension',
'as_attachment', 'tags', 'as_attachment', 'owner', 'tags',
) )
class SavedFilterImportForm(CSVModelForm): class SavedFilterImportForm(OwnerCSVMixin, CSVModelForm):
object_types = CSVMultipleContentTypeField( object_types = CSVMultipleContentTypeField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.all(), queryset=ObjectType.objects.all(),
@@ -179,21 +179,21 @@ class SavedFilterImportForm(CSVModelForm):
class Meta: class Meta:
model = SavedFilter model = SavedFilter
fields = ( fields = (
'name', 'slug', 'object_types', 'description', 'weight', 'enabled', 'shared', 'parameters', 'name', 'slug', 'object_types', 'description', 'weight', 'enabled', 'shared', 'parameters', 'owner',
) )
class WebhookImportForm(NetBoxModelImportForm): class WebhookImportForm(OwnerCSVMixin, NetBoxModelImportForm):
class Meta: class Meta:
model = Webhook model = Webhook
fields = ( fields = (
'name', 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template', 'name', 'payload_url', 'http_method', 'http_content_type', 'additional_headers', 'body_template',
'secret', 'ssl_verification', 'ca_file_path', 'description', 'tags' 'secret', 'ssl_verification', 'ca_file_path', 'description', 'owner', 'tags'
) )
class EventRuleImportForm(NetBoxModelImportForm): class EventRuleImportForm(OwnerCSVMixin, NetBoxModelImportForm):
object_types = CSVMultipleContentTypeField( object_types = CSVMultipleContentTypeField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('event_rules'), queryset=ObjectType.objects.with_feature('event_rules'),
@@ -214,7 +214,7 @@ class EventRuleImportForm(NetBoxModelImportForm):
model = EventRule model = EventRule
fields = ( fields = (
'name', 'description', 'enabled', 'conditions', 'object_types', 'event_types', 'action_type', 'name', 'description', 'enabled', 'conditions', 'object_types', 'event_types', 'action_type',
'comments', 'tags' 'owner', 'comments', 'tags'
) )
def clean(self): def clean(self):
@@ -242,7 +242,7 @@ class EventRuleImportForm(NetBoxModelImportForm):
self.instance.action_object_type = ObjectType.objects.get_for_model(script, for_concrete_model=False) self.instance.action_object_type = ObjectType.objects.get_for_model(script, for_concrete_model=False)
class TagImportForm(CSVModelForm): class TagImportForm(OwnerCSVMixin, CSVModelForm):
slug = SlugField() slug = SlugField()
weight = forms.IntegerField( weight = forms.IntegerField(
label=_('Weight'), label=_('Weight'),
@@ -258,7 +258,7 @@ class TagImportForm(CSVModelForm):
class Meta: class Meta:
model = Tag model = Tag
fields = ( fields = (
'name', 'slug', 'color', 'weight', 'description', 'object_types', 'name', 'slug', 'color', 'weight', 'description', 'object_types', 'owner',
) )

View File

@@ -6,13 +6,14 @@ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site
from extras.choices import * from extras.choices import *
from extras.models import * from extras.models import *
from netbox.events import get_event_type_choices from netbox.events import get_event_type_choices
from netbox.forms.base import NetBoxModelFilterSetForm from netbox.forms import NetBoxModelFilterSetForm, PrimaryModelFilterSetForm
from netbox.forms.mixins import SavedFiltersMixin from netbox.forms.mixins import SavedFiltersMixin
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from users.models import Group, User from users.models import Group, Owner, User
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, FilterForm, add_blank_choice
from utilities.forms.fields import ( from utilities.forms.fields import (
ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelMultipleChoiceField, TagFilterField, ContentTypeChoiceField, ContentTypeMultipleChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
TagFilterField,
) )
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
from utilities.forms.widgets import DateTimePicker from utilities.forms.widgets import DateTimePicker
@@ -115,6 +116,11 @@ class CustomFieldFilterForm(SavedFiltersMixin, FilterForm):
label=_('Validation regex'), label=_('Validation regex'),
required=False required=False
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm): class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm):
@@ -130,6 +136,11 @@ class CustomFieldChoiceSetFilterForm(SavedFiltersMixin, FilterForm):
choice = forms.CharField( choice = forms.CharField(
required=False required=False
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class CustomLinkFilterForm(SavedFiltersMixin, FilterForm): class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
@@ -161,6 +172,11 @@ class CustomLinkFilterForm(SavedFiltersMixin, FilterForm):
label=_('Weight'), label=_('Weight'),
required=False required=False
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm): class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
@@ -207,6 +223,11 @@ class ExportTemplateFilterForm(SavedFiltersMixin, FilterForm):
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
) )
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm): class ImageAttachmentFilterForm(SavedFiltersMixin, FilterForm):
@@ -255,6 +276,11 @@ class SavedFilterFilterForm(SavedFiltersMixin, FilterForm):
label=_('Weight'), label=_('Weight'),
required=False required=False
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class TableConfigFilterForm(SavedFiltersMixin, FilterForm): class TableConfigFilterForm(SavedFiltersMixin, FilterForm):
@@ -290,7 +316,7 @@ class TableConfigFilterForm(SavedFiltersMixin, FilterForm):
class WebhookFilterForm(NetBoxModelFilterSetForm): class WebhookFilterForm(NetBoxModelFilterSetForm):
model = Webhook model = Webhook
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('payload_url', 'http_method', 'http_content_type', name=_('Attributes')), FieldSet('payload_url', 'http_method', 'http_content_type', name=_('Attributes')),
) )
http_content_type = forms.CharField( http_content_type = forms.CharField(
@@ -306,15 +332,18 @@ class WebhookFilterForm(NetBoxModelFilterSetForm):
required=False, required=False,
label=_('HTTP method') label=_('HTTP method')
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
tag = TagFilterField(model) tag = TagFilterField(model)
class EventRuleFilterForm(NetBoxModelFilterSetForm): class EventRuleFilterForm(NetBoxModelFilterSetForm):
model = EventRule model = EventRule
tag = TagFilterField(model)
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('object_type_id', 'event_type', 'action_type', 'enabled', name=_('Attributes')), FieldSet('object_type_id', 'event_type', 'action_type', 'enabled', name=_('Attributes')),
) )
object_type_id = ContentTypeMultipleChoiceField( object_type_id = ContentTypeMultipleChoiceField(
@@ -339,6 +368,12 @@ class EventRuleFilterForm(NetBoxModelFilterSetForm):
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
) )
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
tag = TagFilterField(model)
class TagFilterForm(SavedFiltersMixin, FilterForm): class TagFilterForm(SavedFiltersMixin, FilterForm):
@@ -353,9 +388,14 @@ class TagFilterForm(SavedFiltersMixin, FilterForm):
required=False, required=False,
label=_('Allowed object type') label=_('Allowed object type')
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class ConfigContextProfileFilterForm(SavedFiltersMixin, FilterForm): class ConfigContextProfileFilterForm(PrimaryModelFilterSetForm):
model = ConfigContextProfile model = ConfigContextProfile
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id'), FieldSet('q', 'filter_id'),
@@ -470,6 +510,11 @@ class ConfigContextFilterForm(SavedFiltersMixin, FilterForm):
required=False, required=False,
label=_('Tags') label=_('Tags')
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm): class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
@@ -512,6 +557,11 @@ class ConfigTemplateFilterForm(SavedFiltersMixin, FilterForm):
choices=BOOLEAN_WITH_BLANK_CHOICES choices=BOOLEAN_WITH_BLANK_CHOICES
) )
) )
owner_id = DynamicModelChoiceField(
queryset=Owner.objects.all(),
required=False,
label=_('Owner'),
)
class LocalConfigContextFilterForm(forms.Form): class LocalConfigContextFilterForm(forms.Form):

View File

@@ -12,8 +12,8 @@ from dcim.models import DeviceRole, DeviceType, Location, Platform, Region, Site
from extras.choices import * from extras.choices import *
from extras.models import * from extras.models import *
from netbox.events import get_event_type_choices from netbox.events import get_event_type_choices
from netbox.forms import NetBoxModelForm from netbox.forms import NetBoxModelForm, PrimaryModelForm
from netbox.forms.mixins import ChangelogMessageMixin from netbox.forms.mixins import ChangelogMessageMixin, OwnerMixin
from tenancy.models import Tenant, TenantGroup from tenancy.models import Tenant, TenantGroup
from users.models import Group, User from users.models import Group, User
from utilities.forms import get_field_value from utilities.forms import get_field_value
@@ -47,7 +47,7 @@ __all__ = (
) )
class CustomFieldForm(ChangelogMessageMixin, forms.ModelForm): class CustomFieldForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
object_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_fields'), queryset=ObjectType.objects.with_feature('custom_fields'),
@@ -166,7 +166,7 @@ class CustomFieldForm(ChangelogMessageMixin, forms.ModelForm):
del self.fields['choice_set'] del self.fields['choice_set']
class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm): class CustomFieldChoiceSetForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
# TODO: The extra_choices field definition diverge from the CustomFieldChoiceSet model # TODO: The extra_choices field definition diverge from the CustomFieldChoiceSet model
extra_choices = forms.CharField( extra_choices = forms.CharField(
widget=ChoicesWidget(), widget=ChoicesWidget(),
@@ -179,7 +179,7 @@ class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm):
class Meta: class Meta:
model = CustomFieldChoiceSet model = CustomFieldChoiceSet
fields = ('name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically') fields = ('name', 'description', 'base_choices', 'extra_choices', 'order_alphabetically', 'owner')
def __init__(self, *args, initial=None, **kwargs): def __init__(self, *args, initial=None, **kwargs):
super().__init__(*args, initial=initial, **kwargs) super().__init__(*args, initial=initial, **kwargs)
@@ -219,7 +219,7 @@ class CustomFieldChoiceSetForm(ChangelogMessageMixin, forms.ModelForm):
return data return data
class CustomLinkForm(ChangelogMessageMixin, forms.ModelForm): class CustomLinkForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
object_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('custom_links') queryset=ObjectType.objects.with_feature('custom_links')
@@ -251,7 +251,7 @@ class CustomLinkForm(ChangelogMessageMixin, forms.ModelForm):
} }
class ExportTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm): class ExportTemplateForm(ChangelogMessageMixin, SyncedDataMixin, OwnerMixin, forms.ModelForm):
object_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('export_templates') queryset=ObjectType.objects.with_feature('export_templates')
@@ -293,7 +293,7 @@ class ExportTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm
return self.cleaned_data return self.cleaned_data
class SavedFilterForm(ChangelogMessageMixin, forms.ModelForm): class SavedFilterForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
slug = SlugField() slug = SlugField()
object_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Object types'), label=_('Object types'),
@@ -427,7 +427,7 @@ class SubscriptionForm(forms.ModelForm):
fields = ('object_type', 'object_id') fields = ('object_type', 'object_id')
class WebhookForm(NetBoxModelForm): class WebhookForm(OwnerMixin, NetBoxModelForm):
fieldsets = ( fieldsets = (
FieldSet('name', 'description', 'tags', name=_('Webhook')), FieldSet('name', 'description', 'tags', name=_('Webhook')),
@@ -447,7 +447,7 @@ class WebhookForm(NetBoxModelForm):
} }
class EventRuleForm(NetBoxModelForm): class EventRuleForm(OwnerMixin, NetBoxModelForm):
object_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Object types'), label=_('Object types'),
queryset=ObjectType.objects.with_feature('event_rules'), queryset=ObjectType.objects.with_feature('event_rules'),
@@ -480,7 +480,7 @@ class EventRuleForm(NetBoxModelForm):
model = EventRule model = EventRule
fields = ( fields = (
'object_types', 'name', 'description', 'enabled', 'event_types', 'conditions', 'action_type', 'object_types', 'name', 'description', 'enabled', 'event_types', 'conditions', 'action_type',
'action_object_type', 'action_object_id', 'action_data', 'comments', 'tags' 'action_object_type', 'action_object_id', 'action_data', 'owner', 'comments', 'tags'
) )
widgets = { widgets = {
'conditions': forms.Textarea(attrs={'class': 'font-monospace'}), 'conditions': forms.Textarea(attrs={'class': 'font-monospace'}),
@@ -563,7 +563,7 @@ class EventRuleForm(NetBoxModelForm):
return self.cleaned_data return self.cleaned_data
class TagForm(ChangelogMessageMixin, forms.ModelForm): class TagForm(ChangelogMessageMixin, OwnerMixin, forms.ModelForm):
slug = SlugField() slug = SlugField()
object_types = ContentTypeMultipleChoiceField( object_types = ContentTypeMultipleChoiceField(
label=_('Object types'), label=_('Object types'),
@@ -582,11 +582,11 @@ class TagForm(ChangelogMessageMixin, forms.ModelForm):
class Meta: class Meta:
model = Tag model = Tag
fields = [ fields = [
'name', 'slug', 'color', 'weight', 'description', 'object_types', 'name', 'slug', 'color', 'weight', 'description', 'object_types', 'owner',
] ]
class ConfigContextProfileForm(SyncedDataMixin, NetBoxModelForm): class ConfigContextProfileForm(SyncedDataMixin, PrimaryModelForm):
schema = JSONField( schema = JSONField(
label=_('Schema'), label=_('Schema'),
required=False, required=False,
@@ -606,11 +606,12 @@ class ConfigContextProfileForm(SyncedDataMixin, NetBoxModelForm):
class Meta: class Meta:
model = ConfigContextProfile model = ConfigContextProfile
fields = ( fields = (
'name', 'description', 'schema', 'data_source', 'data_file', 'auto_sync_enabled', 'comments', 'tags', 'name', 'description', 'schema', 'data_source', 'data_file', 'auto_sync_enabled', 'owner', 'comments',
'tags',
) )
class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm): class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, OwnerMixin, forms.ModelForm):
profile = DynamicModelChoiceField( profile = DynamicModelChoiceField(
label=_('Profile'), label=_('Profile'),
queryset=ConfigContextProfile.objects.all(), queryset=ConfigContextProfile.objects.all(),
@@ -701,7 +702,7 @@ class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm)
fields = ( fields = (
'name', 'weight', 'profile', 'description', 'data', 'is_active', 'regions', 'site_groups', 'sites', 'name', 'weight', 'profile', 'description', 'data', 'is_active', 'regions', 'site_groups', 'sites',
'locations', 'roles', 'device_types', 'platforms', 'cluster_types', 'cluster_groups', 'clusters', 'locations', 'roles', 'device_types', 'platforms', 'cluster_types', 'cluster_groups', 'clusters',
'tenant_groups', 'tenants', 'tags', 'data_source', 'data_file', 'auto_sync_enabled', 'tenant_groups', 'tenants', 'owner', 'tags', 'data_source', 'data_file', 'auto_sync_enabled',
) )
def __init__(self, *args, initial=None, **kwargs): def __init__(self, *args, initial=None, **kwargs):
@@ -727,7 +728,7 @@ class ConfigContextForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm)
return self.cleaned_data return self.cleaned_data
class ConfigTemplateForm(ChangelogMessageMixin, SyncedDataMixin, forms.ModelForm): class ConfigTemplateForm(ChangelogMessageMixin, SyncedDataMixin, OwnerMixin, forms.ModelForm):
tags = DynamicModelMultipleChoiceField( tags = DynamicModelMultipleChoiceField(
label=_('Tags'), label=_('Tags'),
queryset=Tag.objects.all(), queryset=Tag.objects.all(),

View File

@@ -6,7 +6,8 @@ import strawberry_django
from core.graphql.mixins import SyncedDataMixin from core.graphql.mixins import SyncedDataMixin
from extras import models from extras import models
from extras.graphql.mixins import CustomFieldsMixin, TagsMixin from extras.graphql.mixins import CustomFieldsMixin, TagsMixin
from netbox.graphql.types import BaseObjectType, ContentTypeType, NetBoxObjectType, ObjectType, OrganizationalObjectType from netbox.graphql.types import BaseObjectType, ContentTypeType, ObjectType, PrimaryObjectType
from users.graphql.mixins import OwnerMixin
from .filters import * from .filters import *
if TYPE_CHECKING: if TYPE_CHECKING:
@@ -51,7 +52,7 @@ __all__ = (
filters=ConfigContextProfileFilter, filters=ConfigContextProfileFilter,
pagination=True pagination=True
) )
class ConfigContextProfileType(SyncedDataMixin, NetBoxObjectType): class ConfigContextProfileType(SyncedDataMixin, PrimaryObjectType):
pass pass
@@ -61,7 +62,7 @@ class ConfigContextProfileType(SyncedDataMixin, NetBoxObjectType):
filters=ConfigContextFilter, filters=ConfigContextFilter,
pagination=True pagination=True
) )
class ConfigContextType(SyncedDataMixin, ObjectType): class ConfigContextType(SyncedDataMixin, OwnerMixin, ObjectType):
profile: ConfigContextProfileType | None profile: ConfigContextProfileType | None
roles: List[Annotated["DeviceRoleType", strawberry.lazy('dcim.graphql.types')]] roles: List[Annotated["DeviceRoleType", strawberry.lazy('dcim.graphql.types')]]
device_types: List[Annotated["DeviceTypeType", strawberry.lazy('dcim.graphql.types')]] device_types: List[Annotated["DeviceTypeType", strawberry.lazy('dcim.graphql.types')]]
@@ -84,7 +85,7 @@ class ConfigContextType(SyncedDataMixin, ObjectType):
filters=ConfigTemplateFilter, filters=ConfigTemplateFilter,
pagination=True pagination=True
) )
class ConfigTemplateType(SyncedDataMixin, TagsMixin, ObjectType): class ConfigTemplateType(SyncedDataMixin, OwnerMixin, TagsMixin, ObjectType):
virtualmachines: List[Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')]] virtualmachines: List[Annotated["VirtualMachineType", strawberry.lazy('virtualization.graphql.types')]]
devices: List[Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')]] devices: List[Annotated["DeviceType", strawberry.lazy('dcim.graphql.types')]]
platforms: List[Annotated["PlatformType", strawberry.lazy('dcim.graphql.types')]] platforms: List[Annotated["PlatformType", strawberry.lazy('dcim.graphql.types')]]
@@ -97,7 +98,7 @@ class ConfigTemplateType(SyncedDataMixin, TagsMixin, ObjectType):
filters=CustomFieldFilter, filters=CustomFieldFilter,
pagination=True pagination=True
) )
class CustomFieldType(ObjectType): class CustomFieldType(OwnerMixin, ObjectType):
related_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None related_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None
choice_set: Annotated["CustomFieldChoiceSetType", strawberry.lazy('extras.graphql.types')] | None choice_set: Annotated["CustomFieldChoiceSetType", strawberry.lazy('extras.graphql.types')] | None
@@ -108,7 +109,7 @@ class CustomFieldType(ObjectType):
filters=CustomFieldChoiceSetFilter, filters=CustomFieldChoiceSetFilter,
pagination=True pagination=True
) )
class CustomFieldChoiceSetType(ObjectType): class CustomFieldChoiceSetType(OwnerMixin, ObjectType):
choices_for: List[Annotated["CustomFieldType", strawberry.lazy('extras.graphql.types')]] choices_for: List[Annotated["CustomFieldType", strawberry.lazy('extras.graphql.types')]]
extra_choices: List[List[str]] | None extra_choices: List[List[str]] | None
@@ -120,7 +121,7 @@ class CustomFieldChoiceSetType(ObjectType):
filters=CustomLinkFilter, filters=CustomLinkFilter,
pagination=True pagination=True
) )
class CustomLinkType(ObjectType): class CustomLinkType(OwnerMixin, ObjectType):
pass pass
@@ -130,7 +131,7 @@ class CustomLinkType(ObjectType):
filters=ExportTemplateFilter, filters=ExportTemplateFilter,
pagination=True pagination=True
) )
class ExportTemplateType(SyncedDataMixin, ObjectType): class ExportTemplateType(SyncedDataMixin, OwnerMixin, ObjectType):
pass pass
@@ -180,7 +181,7 @@ class NotificationGroupType(ObjectType):
filters=SavedFilterFilter, filters=SavedFilterFilter,
pagination=True pagination=True
) )
class SavedFilterType(ObjectType): class SavedFilterType(OwnerMixin, ObjectType):
user: Annotated["UserType", strawberry.lazy('users.graphql.types')] | None user: Annotated["UserType", strawberry.lazy('users.graphql.types')] | None
@@ -209,7 +210,7 @@ class TableConfigType(ObjectType):
filters=TagFilter, filters=TagFilter,
pagination=True pagination=True
) )
class TagType(ObjectType): class TagType(OwnerMixin, ObjectType):
color: str color: str
object_types: List[ContentTypeType] object_types: List[ContentTypeType]
@@ -221,7 +222,7 @@ class TagType(ObjectType):
filters=WebhookFilter, filters=WebhookFilter,
pagination=True pagination=True
) )
class WebhookType(OrganizationalObjectType): class WebhookType(OwnerMixin, CustomFieldsMixin, TagsMixin, ObjectType):
pass pass
@@ -231,5 +232,5 @@ class WebhookType(OrganizationalObjectType):
filters=EventRuleFilter, filters=EventRuleFilter,
pagination=True pagination=True
) )
class EventRuleType(OrganizationalObjectType): class EventRuleType(OwnerMixin, CustomFieldsMixin, TagsMixin, ObjectType):
action_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None action_object_type: Annotated["ContentTypeType", strawberry.lazy('netbox.graphql.types')] | None

View File

@@ -0,0 +1,89 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('extras', '0133_make_cf_minmax_decimal'),
('users', '0015_owner'),
]
operations = [
migrations.AddField(
model_name='configcontext',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='configcontextprofile',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='configtemplate',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='customfield',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='customfieldchoiceset',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='customlink',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='eventrule',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='exporttemplate',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='savedfilter',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='tag',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='webhook',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
]

View File

@@ -13,6 +13,7 @@ from extras.models.mixins import RenderTemplateMixin
from extras.querysets import ConfigContextQuerySet from extras.querysets import ConfigContextQuerySet
from netbox.models import ChangeLoggedModel, PrimaryModel from netbox.models import ChangeLoggedModel, PrimaryModel
from netbox.models.features import CloningMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin from netbox.models.features import CloningMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin
from netbox.models.mixins import OwnerMixin
from utilities.data import deepmerge from utilities.data import deepmerge
from utilities.jsonschema import validate_schema from utilities.jsonschema import validate_schema
@@ -68,7 +69,7 @@ class ConfigContextProfile(SyncedDataMixin, PrimaryModel):
sync_data.alters_data = True sync_data.alters_data = True
class ConfigContext(SyncedDataMixin, CloningMixin, CustomLinksMixin, ChangeLoggedModel): class ConfigContext(SyncedDataMixin, CloningMixin, CustomLinksMixin, OwnerMixin, ChangeLoggedModel):
""" """
A ConfigContext represents a set of arbitrary data available to any Device or VirtualMachine matching its assigned A ConfigContext represents a set of arbitrary data available to any Device or VirtualMachine matching its assigned
qualifiers (region, site, etc.). For example, the data stored in a ConfigContext assigned to site A and tenant B qualifiers (region, site, etc.). For example, the data stored in a ConfigContext assigned to site A and tenant B
@@ -266,7 +267,13 @@ class ConfigContextModel(models.Model):
# #
class ConfigTemplate( class ConfigTemplate(
RenderTemplateMixin, SyncedDataMixin, CustomLinksMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel RenderTemplateMixin,
SyncedDataMixin,
CustomLinksMixin,
ExportTemplatesMixin,
OwnerMixin,
TagsMixin,
ChangeLoggedModel,
): ):
name = models.CharField( name = models.CharField(
verbose_name=_('name'), verbose_name=_('name'),

View File

@@ -21,6 +21,7 @@ from extras.choices import *
from extras.data import CHOICE_SETS from extras.data import CHOICE_SETS
from netbox.models import ChangeLoggedModel from netbox.models import ChangeLoggedModel
from netbox.models.features import CloningMixin, ExportTemplatesMixin from netbox.models.features import CloningMixin, ExportTemplatesMixin
from netbox.models.mixins import OwnerMixin
from netbox.search import FieldTypes from netbox.search import FieldTypes
from utilities import filters from utilities import filters
from utilities.datetime import datetime_from_timestamp from utilities.datetime import datetime_from_timestamp
@@ -70,7 +71,7 @@ class CustomFieldManager(models.Manager.from_queryset(RestrictedQuerySet)):
} }
class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): class CustomField(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel):
object_types = models.ManyToManyField( object_types = models.ManyToManyField(
to='contenttypes.ContentType', to='contenttypes.ContentType',
related_name='custom_fields', related_name='custom_fields',
@@ -773,7 +774,7 @@ class CustomField(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
raise ValidationError(_("Required field cannot be empty.")) raise ValidationError(_("Required field cannot be empty."))
class CustomFieldChoiceSet(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): class CustomFieldChoiceSet(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel):
""" """
Represents a set of choices available for choice and multi-choice custom fields. Represents a set of choices available for choice and multi-choice custom fields.
""" """

View File

@@ -25,6 +25,7 @@ from netbox.models import ChangeLoggedModel
from netbox.models.features import ( from netbox.models.features import (
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin, has_feature CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin, has_feature
) )
from netbox.models.mixins import OwnerMixin
from utilities.html import clean_html from utilities.html import clean_html
from utilities.jinja2 import render_jinja2 from utilities.jinja2 import render_jinja2
from utilities.querydict import dict_to_querydict from utilities.querydict import dict_to_querydict
@@ -44,7 +45,7 @@ __all__ = (
) )
class EventRule(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel): class EventRule(CustomFieldsMixin, ExportTemplatesMixin, OwnerMixin, TagsMixin, ChangeLoggedModel):
""" """
An EventRule defines an action to be taken automatically in response to a specific set of events, such as when a An EventRule defines an action to be taken automatically in response to a specific set of events, such as when a
specific type of object is created, modified, or deleted. The action to be taken might entail transmitting a specific type of object is created, modified, or deleted. The action to be taken might entail transmitting a
@@ -155,7 +156,7 @@ class EventRule(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLogged
return False return False
class Webhook(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedModel): class Webhook(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, OwnerMixin, ChangeLoggedModel):
""" """
A Webhook defines a request that will be sent to a remote application when an object is created, updated, and/or A Webhook defines a request that will be sent to a remote application when an object is created, updated, and/or
delete in NetBox. The request will contain a representation of the object, which the remote application can act on. delete in NetBox. The request will contain a representation of the object, which the remote application can act on.
@@ -294,7 +295,7 @@ class Webhook(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, ChangeLoggedMo
return render_jinja2(self.payload_url, context) return render_jinja2(self.payload_url, context)
class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): class CustomLink(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel):
""" """
A custom link to an external representation of a NetBox object. The link text and URL fields accept Jinja2 template A custom link to an external representation of a NetBox object. The link text and URL fields accept Jinja2 template
code to be rendered with an object as context. code to be rendered with an object as context.
@@ -394,7 +395,14 @@ class CustomLink(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel):
} }
class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, RenderTemplateMixin): class ExportTemplate(
SyncedDataMixin,
CloningMixin,
ExportTemplatesMixin,
OwnerMixin,
ChangeLoggedModel,
RenderTemplateMixin,
):
object_types = models.ManyToManyField( object_types = models.ManyToManyField(
to='contenttypes.ContentType', to='contenttypes.ContentType',
related_name='export_templates', related_name='export_templates',
@@ -456,7 +464,7 @@ class ExportTemplate(SyncedDataMixin, CloningMixin, ExportTemplatesMixin, Change
return _context return _context
class SavedFilter(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel): class SavedFilter(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel):
""" """
A set of predefined keyword parameters that can be reused to filter for specific objects. A set of predefined keyword parameters that can be reused to filter for specific objects.
""" """

View File

@@ -8,6 +8,7 @@ from taggit.models import TagBase, GenericTaggedItemBase
from netbox.choices import ColorChoices from netbox.choices import ColorChoices
from netbox.models import ChangeLoggedModel from netbox.models import ChangeLoggedModel
from netbox.models.features import CloningMixin, ExportTemplatesMixin from netbox.models.features import CloningMixin, ExportTemplatesMixin
from netbox.models.mixins import OwnerMixin
from utilities.fields import ColorField from utilities.fields import ColorField
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
@@ -21,7 +22,7 @@ __all__ = (
# Tags # Tags
# #
class Tag(CloningMixin, ExportTemplatesMixin, ChangeLoggedModel, TagBase): class Tag(CloningMixin, ExportTemplatesMixin, OwnerMixin, ChangeLoggedModel, TagBase):
id = models.BigAutoField( id = models.BigAutoField(
primary_key=True primary_key=True
) )

View File

@@ -10,7 +10,7 @@ from core.tables import JobTable
from core.models import Job from core.models import Job
from netbox.constants import EMPTY_TABLE_TEXT from netbox.constants import EMPTY_TABLE_TEXT
from netbox.events import get_event_text from netbox.events import get_event_text
from netbox.tables import BaseTable, NetBoxTable, columns from netbox.tables import BaseTable, NetBoxTable, PrimaryModelTable, columns
from .columns import NotificationActionsColumn from .columns import NotificationActionsColumn
__all__ = ( __all__ = (
@@ -109,6 +109,10 @@ class CustomFieldTable(NetBoxTable):
validation_regex = tables.Column( validation_regex = tables.Column(
verbose_name=_('Validation Regex'), verbose_name=_('Validation Regex'),
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = CustomField model = CustomField
@@ -146,6 +150,10 @@ class CustomFieldChoiceSetTable(NetBoxTable):
verbose_name=_('Order Alphabetically'), verbose_name=_('Order Alphabetically'),
false_mark=None false_mark=None
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = CustomFieldChoiceSet model = CustomFieldChoiceSet
@@ -171,6 +179,10 @@ class CustomLinkTable(NetBoxTable):
verbose_name=_('New Window'), verbose_name=_('New Window'),
false_mark=None false_mark=None
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = CustomLink model = CustomLink
@@ -214,6 +226,10 @@ class ExportTemplateTable(NetBoxTable):
orderable=False, orderable=False,
verbose_name=_('Synced') verbose_name=_('Synced')
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = ExportTemplate model = ExportTemplate
@@ -294,6 +310,10 @@ class SavedFilterTable(NetBoxTable):
verbose_name=_('Shared'), verbose_name=_('Shared'),
false_mark=None false_mark=None
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
def value_parameters(self, value): def value_parameters(self, value):
return json.dumps(value) return json.dumps(value)
@@ -450,6 +470,10 @@ class WebhookTable(NetBoxTable):
ssl_validation = columns.BooleanColumn( ssl_validation = columns.BooleanColumn(
verbose_name=_('SSL Validation') verbose_name=_('SSL Validation')
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='extras:webhook_list' url_name='extras:webhook_list'
) )
@@ -488,6 +512,10 @@ class EventRuleTable(NetBoxTable):
func=get_event_text, func=get_event_text,
orderable=False orderable=False
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='extras:webhook_list' url_name='extras:webhook_list'
) )
@@ -514,6 +542,10 @@ class TagTable(NetBoxTable):
object_types = columns.ContentTypesColumn( object_types = columns.ContentTypesColumn(
verbose_name=_('Object Types'), verbose_name=_('Object Types'),
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
class Meta(NetBoxTable.Meta): class Meta(NetBoxTable.Meta):
model = Tag model = Tag
@@ -547,7 +579,7 @@ class TaggedItemTable(NetBoxTable):
fields = ('id', 'content_type', 'content_object') fields = ('id', 'content_type', 'content_object')
class ConfigContextProfileTable(NetBoxTable): class ConfigContextProfileTable(PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -568,7 +600,7 @@ class ConfigContextProfileTable(NetBoxTable):
url_name='extras:configcontextprofile_list' url_name='extras:configcontextprofile_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = ConfigContextProfile model = ConfigContextProfile
fields = ( fields = (
'pk', 'id', 'name', 'description', 'comments', 'data_source', 'data_file', 'is_synced', 'tags', 'created', 'pk', 'id', 'name', 'description', 'comments', 'data_source', 'data_file', 'is_synced', 'tags', 'created',
@@ -601,6 +633,10 @@ class ConfigContextTable(NetBoxTable):
orderable=False, orderable=False,
verbose_name=_('Synced') verbose_name=_('Synced')
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='extras:configcontext_list' url_name='extras:configcontext_list'
) )
@@ -645,6 +681,10 @@ class ConfigTemplateTable(NetBoxTable):
verbose_name=_('As Attachment'), verbose_name=_('As Attachment'),
false_mark=None false_mark=None
) )
owner = tables.Column(
linkify=True,
verbose_name=_('Owner')
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='extras:configtemplate_list' url_name='extras:configtemplate_list'
) )

View File

@@ -2,7 +2,7 @@ from rest_framework import serializers
from ipam.models import ASN, ASNRange, RIR from ipam.models import ASN, ASNRange, RIR
from netbox.api.fields import RelatedObjectCountField from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import OrganizationalModelSerializer, PrimaryModelSerializer
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
__all__ = ( __all__ = (
@@ -13,7 +13,7 @@ __all__ = (
) )
class RIRSerializer(NetBoxModelSerializer): class RIRSerializer(OrganizationalModelSerializer):
# Related object counts # Related object counts
aggregate_count = RelatedObjectCountField('aggregates') aggregate_count = RelatedObjectCountField('aggregates')
@@ -21,13 +21,13 @@ class RIRSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = RIR model = RIR
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'is_private', 'description', 'tags', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'is_private', 'description', 'owner', 'tags',
'custom_fields', 'created', 'last_updated', 'aggregate_count', 'custom_fields', 'created', 'last_updated', 'aggregate_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'aggregate_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'aggregate_count')
class ASNRangeSerializer(NetBoxModelSerializer): class ASNRangeSerializer(OrganizationalModelSerializer):
rir = RIRSerializer(nested=True) rir = RIRSerializer(nested=True)
tenant = TenantSerializer(nested=True, required=False, allow_null=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True)
asn_count = serializers.IntegerField(read_only=True) asn_count = serializers.IntegerField(read_only=True)
@@ -36,12 +36,12 @@ class ASNRangeSerializer(NetBoxModelSerializer):
model = ASNRange model = ASNRange
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'rir', 'start', 'end', 'tenant', 'description', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'rir', 'start', 'end', 'tenant', 'description',
'tags', 'custom_fields', 'created', 'last_updated', 'asn_count', 'owner', 'tags', 'custom_fields', 'created', 'last_updated', 'asn_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')
class ASNSerializer(NetBoxModelSerializer): class ASNSerializer(PrimaryModelSerializer):
rir = RIRSerializer(nested=True, required=False, allow_null=True) rir = RIRSerializer(nested=True, required=False, allow_null=True)
tenant = TenantSerializer(nested=True, required=False, allow_null=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True)
@@ -52,7 +52,7 @@ class ASNSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = ASN model = ASN
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'asn', 'rir', 'tenant', 'description', 'comments', 'tags', 'id', 'url', 'display_url', 'display', 'asn', 'rir', 'tenant', 'description', 'owner', 'comments', 'tags',
'custom_fields', 'created', 'last_updated', 'site_count', 'provider_count', 'custom_fields', 'created', 'last_updated', 'site_count', 'provider_count',
] ]
brief_fields = ('id', 'url', 'display', 'asn', 'description') brief_fields = ('id', 'url', 'display', 'asn', 'description')

View File

@@ -4,7 +4,7 @@ from rest_framework import serializers
from ipam.models import FHRPGroup, FHRPGroupAssignment from ipam.models import FHRPGroup, FHRPGroupAssignment
from netbox.api.fields import ContentTypeField from netbox.api.fields import ContentTypeField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer, PrimaryModelSerializer
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from .ip import IPAddressSerializer from .ip import IPAddressSerializer
@@ -14,14 +14,14 @@ __all__ = (
) )
class FHRPGroupSerializer(NetBoxModelSerializer): class FHRPGroupSerializer(PrimaryModelSerializer):
ip_addresses = IPAddressSerializer(nested=True, many=True, read_only=True) ip_addresses = IPAddressSerializer(nested=True, many=True, read_only=True)
class Meta: class Meta:
model = FHRPGroup model = FHRPGroup
fields = [ fields = [
'id', 'name', 'url', 'display_url', 'display', 'protocol', 'group_id', 'auth_type', 'auth_key', 'id', 'name', 'url', 'display_url', 'display', 'protocol', 'group_id', 'auth_type', 'auth_key',
'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'ip_addresses', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'ip_addresses',
] ]
brief_fields = ('id', 'url', 'display', 'protocol', 'group_id', 'description') brief_fields = ('id', 'url', 'display', 'protocol', 'group_id', 'description')

View File

@@ -7,7 +7,7 @@ from ipam.choices import *
from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS from ipam.constants import IPADDRESS_ASSIGNMENT_MODELS
from ipam.models import Aggregate, IPAddress, IPRange, Prefix from ipam.models import Aggregate, IPAddress, IPRange, Prefix
from netbox.api.fields import ChoiceField, ContentTypeField from netbox.api.fields import ChoiceField, ContentTypeField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import PrimaryModelSerializer
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from .asns import RIRSerializer from .asns import RIRSerializer
@@ -28,7 +28,7 @@ __all__ = (
) )
class AggregateSerializer(NetBoxModelSerializer): class AggregateSerializer(PrimaryModelSerializer):
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
rir = RIRSerializer(nested=True) rir = RIRSerializer(nested=True)
tenant = TenantSerializer(nested=True, required=False, allow_null=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True)
@@ -38,12 +38,12 @@ class AggregateSerializer(NetBoxModelSerializer):
model = Aggregate model = Aggregate
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'family', 'prefix', 'rir', 'tenant', 'date_added', 'description', 'id', 'url', 'display_url', 'display', 'family', 'prefix', 'rir', 'tenant', 'date_added', 'description',
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description') brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description')
class PrefixSerializer(NetBoxModelSerializer): class PrefixSerializer(PrimaryModelSerializer):
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
vrf = VRFSerializer(nested=True, required=False, allow_null=True) vrf = VRFSerializer(nested=True, required=False, allow_null=True)
scope_type = ContentTypeField( scope_type = ContentTypeField(
@@ -68,7 +68,7 @@ class PrefixSerializer(NetBoxModelSerializer):
model = Prefix model = Prefix
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'family', 'prefix', 'vrf', 'scope_type', 'scope_id', 'scope', 'id', 'url', 'display_url', 'display', 'family', 'prefix', 'vrf', 'scope_type', 'scope_id', 'scope',
'tenant', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'description', 'comments', 'tags', 'tenant', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'description', 'owner', 'comments', 'tags',
'custom_fields', 'created', 'last_updated', 'children', '_depth', 'custom_fields', 'created', 'last_updated', 'children', '_depth',
] ]
brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description', '_depth') brief_fields = ('id', 'url', 'display', 'family', 'prefix', 'description', '_depth')
@@ -133,7 +133,7 @@ class AvailablePrefixSerializer(serializers.Serializer):
# IP ranges # IP ranges
# #
class IPRangeSerializer(NetBoxModelSerializer): class IPRangeSerializer(PrimaryModelSerializer):
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
start_address = IPAddressField() start_address = IPAddressField()
end_address = IPAddressField() end_address = IPAddressField()
@@ -146,7 +146,7 @@ class IPRangeSerializer(NetBoxModelSerializer):
model = IPRange model = IPRange
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'family', 'start_address', 'end_address', 'size', 'vrf', 'tenant', 'id', 'url', 'display_url', 'display', 'family', 'start_address', 'end_address', 'size', 'vrf', 'tenant',
'status', 'role', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'status', 'role', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
'mark_populated', 'mark_utilized', 'mark_populated', 'mark_utilized',
] ]
brief_fields = ('id', 'url', 'display', 'family', 'start_address', 'end_address', 'description') brief_fields = ('id', 'url', 'display', 'family', 'start_address', 'end_address', 'description')
@@ -156,7 +156,7 @@ class IPRangeSerializer(NetBoxModelSerializer):
# IP addresses # IP addresses
# #
class IPAddressSerializer(NetBoxModelSerializer): class IPAddressSerializer(PrimaryModelSerializer):
family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True) family = ChoiceField(choices=IPAddressFamilyChoices, read_only=True)
address = IPAddressField() address = IPAddressField()
vrf = VRFSerializer(nested=True, required=False, allow_null=True) vrf = VRFSerializer(nested=True, required=False, allow_null=True)
@@ -177,7 +177,7 @@ class IPAddressSerializer(NetBoxModelSerializer):
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'family', 'address', 'vrf', 'tenant', 'status', 'role', 'id', 'url', 'display_url', 'display', 'family', 'address', 'vrf', 'tenant', 'status', 'role',
'assigned_object_type', 'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside', 'assigned_object_type', 'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside',
'dns_name', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'dns_name', 'description', 'owner', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'family', 'address', 'description') brief_fields = ('id', 'url', 'display', 'family', 'address', 'description')

View File

@@ -1,13 +1,13 @@
from ipam.models import Role from ipam.models import Role
from netbox.api.fields import RelatedObjectCountField from netbox.api.fields import RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import OrganizationalModelSerializer
__all__ = ( __all__ = (
'RoleSerializer', 'RoleSerializer',
) )
class RoleSerializer(NetBoxModelSerializer): class RoleSerializer(OrganizationalModelSerializer):
# Related object counts # Related object counts
prefix_count = RelatedObjectCountField('prefixes') prefix_count = RelatedObjectCountField('prefixes')
@@ -16,7 +16,7 @@ class RoleSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = Role model = Role
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'weight', 'description', 'tags', 'custom_fields', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'weight', 'description', 'owner', 'tags',
'created', 'last_updated', 'prefix_count', 'vlan_count', 'custom_fields', 'created', 'last_updated', 'prefix_count', 'vlan_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'prefix_count', 'vlan_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'prefix_count', 'vlan_count')

View File

@@ -6,7 +6,7 @@ from ipam.choices import *
from ipam.constants import SERVICE_ASSIGNMENT_MODELS from ipam.constants import SERVICE_ASSIGNMENT_MODELS
from ipam.models import IPAddress, Service, ServiceTemplate from ipam.models import IPAddress, Service, ServiceTemplate
from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import PrimaryModelSerializer
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from .ip import IPAddressSerializer from .ip import IPAddressSerializer
@@ -16,19 +16,19 @@ __all__ = (
) )
class ServiceTemplateSerializer(NetBoxModelSerializer): class ServiceTemplateSerializer(PrimaryModelSerializer):
protocol = ChoiceField(choices=ServiceProtocolChoices, required=False) protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
class Meta: class Meta:
model = ServiceTemplate model = ServiceTemplate
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'protocol', 'ports', 'description', 'comments', 'tags', 'id', 'url', 'display_url', 'display', 'name', 'protocol', 'ports', 'description', 'owner', 'comments',
'custom_fields', 'created', 'last_updated', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description') brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description')
class ServiceSerializer(NetBoxModelSerializer): class ServiceSerializer(PrimaryModelSerializer):
protocol = ChoiceField(choices=ServiceProtocolChoices, required=False) protocol = ChoiceField(choices=ServiceProtocolChoices, required=False)
ipaddresses = SerializedPKRelatedField( ipaddresses = SerializedPKRelatedField(
queryset=IPAddress.objects.all(), queryset=IPAddress.objects.all(),
@@ -46,7 +46,7 @@ class ServiceSerializer(NetBoxModelSerializer):
model = Service model = Service
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'parent_object_type', 'parent_object_id', 'parent', 'name', 'id', 'url', 'display_url', 'display', 'parent_object_type', 'parent_object_id', 'parent', 'name',
'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags', 'custom_fields', 'protocol', 'ports', 'ipaddresses', 'description', 'owner', 'comments', 'tags', 'custom_fields',
'created', 'last_updated', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description') brief_fields = ('id', 'url', 'display', 'name', 'protocol', 'ports', 'description')

View File

@@ -7,7 +7,7 @@ from ipam.choices import *
from ipam.constants import VLANGROUP_SCOPE_TYPES from ipam.constants import VLANGROUP_SCOPE_TYPES
from ipam.models import VLAN, VLANGroup, VLANTranslationPolicy, VLANTranslationRule from ipam.models import VLAN, VLANGroup, VLANTranslationPolicy, VLANTranslationRule
from netbox.api.fields import ChoiceField, ContentTypeField, IntegerRangeSerializer, RelatedObjectCountField from netbox.api.fields import ChoiceField, ContentTypeField, IntegerRangeSerializer, RelatedObjectCountField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import NetBoxModelSerializer, OrganizationalModelSerializer, PrimaryModelSerializer
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
from utilities.api import get_serializer_for_model from utilities.api import get_serializer_for_model
from vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer from vpn.api.serializers_.l2vpn import L2VPNTerminationSerializer
@@ -24,7 +24,7 @@ __all__ = (
) )
class VLANGroupSerializer(NetBoxModelSerializer): class VLANGroupSerializer(OrganizationalModelSerializer):
scope_type = ContentTypeField( scope_type = ContentTypeField(
queryset=ContentType.objects.filter( queryset=ContentType.objects.filter(
model__in=VLANGROUP_SCOPE_TYPES model__in=VLANGROUP_SCOPE_TYPES
@@ -46,7 +46,8 @@ class VLANGroupSerializer(NetBoxModelSerializer):
model = VLANGroup model = VLANGroup
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'slug', 'scope_type', 'scope_id', 'scope', 'vid_ranges', 'id', 'url', 'display_url', 'display', 'name', 'slug', 'scope_type', 'scope_id', 'scope', 'vid_ranges',
'tenant', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count', 'utilization' 'tenant', 'description', 'owner', 'tags', 'custom_fields', 'created', 'last_updated', 'vlan_count',
'utilization',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'vlan_count') brief_fields = ('id', 'url', 'display', 'name', 'slug', 'description', 'vlan_count')
validators = [] validators = []
@@ -60,7 +61,7 @@ class VLANGroupSerializer(NetBoxModelSerializer):
return serializer(obj.scope, nested=True, context=context).data return serializer(obj.scope, nested=True, context=context).data
class VLANSerializer(NetBoxModelSerializer): class VLANSerializer(PrimaryModelSerializer):
site = SiteSerializer(nested=True, required=False, allow_null=True) site = SiteSerializer(nested=True, required=False, allow_null=True)
group = VLANGroupSerializer(nested=True, required=False, allow_null=True, default=None) group = VLANGroupSerializer(nested=True, required=False, allow_null=True, default=None)
tenant = TenantSerializer(nested=True, required=False, allow_null=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True)
@@ -77,7 +78,7 @@ class VLANSerializer(NetBoxModelSerializer):
model = VLAN model = VLAN
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'id', 'url', 'display_url', 'display', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role',
'description', 'qinq_role', 'qinq_svlan', 'comments', 'l2vpn_termination', 'tags', 'custom_fields', 'description', 'qinq_role', 'qinq_svlan', 'owner', 'comments', 'l2vpn_termination', 'tags', 'custom_fields',
'created', 'last_updated', 'prefix_count', 'created', 'last_updated', 'prefix_count',
] ]
brief_fields = ('id', 'url', 'display', 'vid', 'name', 'description') brief_fields = ('id', 'url', 'display', 'vid', 'name', 'description')
@@ -125,10 +126,10 @@ class VLANTranslationRuleSerializer(NetBoxModelSerializer):
fields = ['id', 'url', 'display', 'policy', 'local_vid', 'remote_vid', 'description'] fields = ['id', 'url', 'display', 'policy', 'local_vid', 'remote_vid', 'description']
class VLANTranslationPolicySerializer(NetBoxModelSerializer): class VLANTranslationPolicySerializer(PrimaryModelSerializer):
rules = VLANTranslationRuleSerializer(many=True, read_only=True) rules = VLANTranslationRuleSerializer(many=True, read_only=True)
class Meta: class Meta:
model = VLANTranslationPolicy model = VLANTranslationPolicy
fields = ['id', 'url', 'display', 'name', 'description', 'display', 'rules'] fields = ['id', 'url', 'display', 'name', 'description', 'display', 'rules', 'owner', 'comments']
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')

View File

@@ -1,6 +1,6 @@
from ipam.models import RouteTarget, VRF from ipam.models import RouteTarget, VRF
from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField from netbox.api.fields import RelatedObjectCountField, SerializedPKRelatedField
from netbox.api.serializers import NetBoxModelSerializer from netbox.api.serializers import PrimaryModelSerializer
from tenancy.api.serializers_.tenants import TenantSerializer from tenancy.api.serializers_.tenants import TenantSerializer
__all__ = ( __all__ = (
@@ -9,19 +9,19 @@ __all__ = (
) )
class RouteTargetSerializer(NetBoxModelSerializer): class RouteTargetSerializer(PrimaryModelSerializer):
tenant = TenantSerializer(nested=True, required=False, allow_null=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True)
class Meta: class Meta:
model = RouteTarget model = RouteTarget
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'tenant', 'description', 'comments', 'tags', 'id', 'url', 'display_url', 'display', 'name', 'tenant', 'description', 'owner', 'comments', 'tags',
'custom_fields', 'created', 'last_updated', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'description') brief_fields = ('id', 'url', 'display', 'name', 'description')
class VRFSerializer(NetBoxModelSerializer): class VRFSerializer(PrimaryModelSerializer):
tenant = TenantSerializer(nested=True, required=False, allow_null=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True)
import_targets = SerializedPKRelatedField( import_targets = SerializedPKRelatedField(
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
@@ -43,8 +43,8 @@ class VRFSerializer(NetBoxModelSerializer):
class Meta: class Meta:
model = VRF model = VRF
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'comments', 'id', 'url', 'display_url', 'display', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'owner',
'import_targets', 'export_targets', 'tags', 'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'comments', 'import_targets', 'export_targets', 'tags', 'custom_fields', 'created', 'last_updated',
'prefix_count', 'ipaddress_count', 'prefix_count',
] ]
brief_fields = ('id', 'url', 'display', 'name', 'rd', 'description', 'prefix_count') brief_fields = ('id', 'url', 'display', 'name', 'rd', 'description', 'prefix_count')

View File

@@ -11,7 +11,9 @@ from netaddr.core import AddrFormatError
from circuits.models import Provider from circuits.models import Provider
from dcim.models import Device, Interface, Region, Site, SiteGroup from dcim.models import Device, Interface, Region, Site, SiteGroup
from netbox.filtersets import ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet from netbox.filtersets import (
ChangeLoggedModelFilterSet, OrganizationalModelFilterSet, NetBoxModelFilterSet, PrimaryModelFilterSet,
)
from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet from tenancy.filtersets import ContactModelFilterSet, TenancyFilterSet
from utilities.filters import ( from utilities.filters import (
@@ -45,7 +47,7 @@ __all__ = (
) )
class VRFFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class VRFFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
import_target_id = django_filters.ModelMultipleChoiceFilter( import_target_id = django_filters.ModelMultipleChoiceFilter(
field_name='import_targets', field_name='import_targets',
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
@@ -83,7 +85,7 @@ class VRFFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
fields = ('id', 'name', 'rd', 'enforce_unique', 'description') fields = ('id', 'name', 'rd', 'enforce_unique', 'description')
class RouteTargetFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class RouteTargetFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
importing_vrf_id = django_filters.ModelMultipleChoiceFilter( importing_vrf_id = django_filters.ModelMultipleChoiceFilter(
field_name='importing_vrfs', field_name='importing_vrfs',
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
@@ -149,7 +151,7 @@ class RIRFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'is_private', 'description') fields = ('id', 'name', 'slug', 'is_private', 'description')
class AggregateFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet): class AggregateFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
family = django_filters.NumberFilter( family = django_filters.NumberFilter(
field_name='prefix', field_name='prefix',
lookup_expr='family' lookup_expr='family'
@@ -221,7 +223,7 @@ class ASNRangeFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
) )
class ASNFilterSet(OrganizationalModelFilterSet, TenancyFilterSet): class ASNFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
rir_id = django_filters.ModelMultipleChoiceFilter( rir_id = django_filters.ModelMultipleChoiceFilter(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
label=_('RIR (ID)'), label=_('RIR (ID)'),
@@ -290,7 +292,7 @@ class RoleFilterSet(OrganizationalModelFilterSet):
fields = ('id', 'name', 'slug', 'description', 'weight') fields = ('id', 'name', 'slug', 'description', 'weight')
class PrefixFilterSet(NetBoxModelFilterSet, ScopedFilterSet, TenancyFilterSet, ContactModelFilterSet): class PrefixFilterSet(PrimaryModelFilterSet, ScopedFilterSet, TenancyFilterSet, ContactModelFilterSet):
family = django_filters.NumberFilter( family = django_filters.NumberFilter(
field_name='prefix', field_name='prefix',
lookup_expr='family' lookup_expr='family'
@@ -456,7 +458,7 @@ class PrefixFilterSet(NetBoxModelFilterSet, ScopedFilterSet, TenancyFilterSet, C
).distinct() ).distinct()
class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet, ContactModelFilterSet): class IPRangeFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
family = django_filters.NumberFilter( family = django_filters.NumberFilter(
field_name='start_address', field_name='start_address',
lookup_expr='family' lookup_expr='family'
@@ -548,7 +550,7 @@ class IPRangeFilterSet(TenancyFilterSet, NetBoxModelFilterSet, ContactModelFilte
return queryset.filter(q) return queryset.filter(q)
class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFilterSet): class IPAddressFilterSet(PrimaryModelFilterSet, TenancyFilterSet, ContactModelFilterSet):
family = django_filters.NumberFilter( family = django_filters.NumberFilter(
field_name='address', field_name='address',
lookup_expr='family' lookup_expr='family'
@@ -784,7 +786,7 @@ class IPAddressFilterSet(NetBoxModelFilterSet, TenancyFilterSet, ContactModelFil
) )
class FHRPGroupFilterSet(NetBoxModelFilterSet): class FHRPGroupFilterSet(PrimaryModelFilterSet):
protocol = django_filters.MultipleChoiceFilter( protocol = django_filters.MultipleChoiceFilter(
choices=FHRPGroupProtocolChoices choices=FHRPGroupProtocolChoices
) )
@@ -934,7 +936,7 @@ class VLANGroupFilterSet(OrganizationalModelFilterSet, TenancyFilterSet):
) )
class VLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet): class VLANFilterSet(PrimaryModelFilterSet, TenancyFilterSet):
region_id = TreeNodeMultipleChoiceFilter( region_id = TreeNodeMultipleChoiceFilter(
queryset=Region.objects.all(), queryset=Region.objects.all(),
field_name='site__region', field_name='site__region',
@@ -1085,7 +1087,7 @@ class VLANFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
).distinct() ).distinct()
class VLANTranslationPolicyFilterSet(NetBoxModelFilterSet): class VLANTranslationPolicyFilterSet(PrimaryModelFilterSet):
class Meta: class Meta:
model = VLANTranslationPolicy model = VLANTranslationPolicy
@@ -1132,7 +1134,7 @@ class VLANTranslationRuleFilterSet(NetBoxModelFilterSet):
return queryset.filter(qs_filter) return queryset.filter(qs_filter)
class ServiceTemplateFilterSet(NetBoxModelFilterSet): class ServiceTemplateFilterSet(PrimaryModelFilterSet):
port = NumericArrayFilter( port = NumericArrayFilter(
field_name='ports', field_name='ports',
lookup_expr='contains' lookup_expr='contains'
@@ -1152,7 +1154,7 @@ class ServiceTemplateFilterSet(NetBoxModelFilterSet):
return queryset.filter(qs_filter) return queryset.filter(qs_filter)
class ServiceFilterSet(ContactModelFilterSet, NetBoxModelFilterSet): class ServiceFilterSet(ContactModelFilterSet, PrimaryModelFilterSet):
parent_object_type = ContentTypeFilter() parent_object_type = ContentTypeFilter()
device = MultiValueCharFilter( device = MultiValueCharFilter(
method='filter_device', method='filter_device',

View File

@@ -9,11 +9,11 @@ from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from ipam.models import * from ipam.models import *
from ipam.models import ASN from ipam.models import ASN
from netbox.forms import NetBoxModelBulkEditForm from netbox.forms import NetBoxModelBulkEditForm, OrganizationalModelBulkEditForm, PrimaryModelBulkEditForm
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms import add_blank_choice, get_field_value from utilities.forms import add_blank_choice, get_field_value
from utilities.forms.fields import ( from utilities.forms.fields import (
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
NumericRangeArrayField, NumericRangeArrayField,
) )
from utilities.forms.rendering import FieldSet from utilities.forms.rendering import FieldSet
@@ -41,7 +41,7 @@ __all__ = (
) )
class VRFBulkEditForm(NetBoxModelBulkEditForm): class VRFBulkEditForm(PrimaryModelBulkEditForm):
tenant = DynamicModelChoiceField( tenant = DynamicModelChoiceField(
label=_('Tenant'), label=_('Tenant'),
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@@ -52,12 +52,6 @@ class VRFBulkEditForm(NetBoxModelBulkEditForm):
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label=_('Enforce unique space') label=_('Enforce unique space')
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = VRF model = VRF
fieldsets = ( fieldsets = (
@@ -66,18 +60,12 @@ class VRFBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('tenant', 'description', 'comments') nullable_fields = ('tenant', 'description', 'comments')
class RouteTargetBulkEditForm(NetBoxModelBulkEditForm): class RouteTargetBulkEditForm(PrimaryModelBulkEditForm):
tenant = DynamicModelChoiceField( tenant = DynamicModelChoiceField(
label=_('Tenant'), label=_('Tenant'),
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = RouteTarget model = RouteTarget
fieldsets = ( fieldsets = (
@@ -86,17 +74,12 @@ class RouteTargetBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('tenant', 'description', 'comments') nullable_fields = ('tenant', 'description', 'comments')
class RIRBulkEditForm(NetBoxModelBulkEditForm): class RIRBulkEditForm(OrganizationalModelBulkEditForm):
is_private = forms.NullBooleanField( is_private = forms.NullBooleanField(
label=_('Is private'), label=_('Is private'),
required=False, required=False,
widget=BulkEditNullBooleanSelect widget=BulkEditNullBooleanSelect
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = RIR model = RIR
fieldsets = ( fieldsets = (
@@ -105,7 +88,7 @@ class RIRBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('is_private', 'description') nullable_fields = ('is_private', 'description')
class ASNRangeBulkEditForm(NetBoxModelBulkEditForm): class ASNRangeBulkEditForm(OrganizationalModelBulkEditForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
required=False, required=False,
@@ -116,11 +99,6 @@ class ASNRangeBulkEditForm(NetBoxModelBulkEditForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = ASNRange model = ASNRange
fieldsets = ( fieldsets = (
@@ -129,7 +107,7 @@ class ASNRangeBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('description',) nullable_fields = ('description',)
class ASNBulkEditForm(NetBoxModelBulkEditForm): class ASNBulkEditForm(PrimaryModelBulkEditForm):
sites = DynamicModelMultipleChoiceField( sites = DynamicModelMultipleChoiceField(
label=_('Sites'), label=_('Sites'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -145,12 +123,6 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm):
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = ASN model = ASN
fieldsets = ( fieldsets = (
@@ -159,7 +131,7 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('tenant', 'description', 'comments') nullable_fields = ('tenant', 'description', 'comments')
class AggregateBulkEditForm(NetBoxModelBulkEditForm): class AggregateBulkEditForm(PrimaryModelBulkEditForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
required=False, required=False,
@@ -174,12 +146,6 @@ class AggregateBulkEditForm(NetBoxModelBulkEditForm):
label=_('Date added'), label=_('Date added'),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Aggregate model = Aggregate
fieldsets = ( fieldsets = (
@@ -188,16 +154,11 @@ class AggregateBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('date_added', 'description', 'comments') nullable_fields = ('date_added', 'description', 'comments')
class RoleBulkEditForm(NetBoxModelBulkEditForm): class RoleBulkEditForm(OrganizationalModelBulkEditForm):
weight = forms.IntegerField( weight = forms.IntegerField(
label=_('Weight'), label=_('Weight'),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = Role model = Role
fieldsets = ( fieldsets = (
@@ -206,7 +167,7 @@ class RoleBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('description',) nullable_fields = ('description',)
class PrefixBulkEditForm(ScopedBulkEditForm, NetBoxModelBulkEditForm): class PrefixBulkEditForm(ScopedBulkEditForm, PrimaryModelBulkEditForm):
vlan_group = DynamicModelChoiceField( vlan_group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
@@ -256,12 +217,6 @@ class PrefixBulkEditForm(ScopedBulkEditForm, NetBoxModelBulkEditForm):
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label=_('Treat as fully utilized') label=_('Treat as fully utilized')
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = Prefix model = Prefix
fieldsets = ( fieldsets = (
@@ -275,7 +230,7 @@ class PrefixBulkEditForm(ScopedBulkEditForm, NetBoxModelBulkEditForm):
) )
class IPRangeBulkEditForm(NetBoxModelBulkEditForm): class IPRangeBulkEditForm(PrimaryModelBulkEditForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
@@ -306,12 +261,6 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm):
widget=BulkEditNullBooleanSelect(), widget=BulkEditNullBooleanSelect(),
label=_('Treat as fully utilized') label=_('Treat as fully utilized')
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = IPRange model = IPRange
fieldsets = ( fieldsets = (
@@ -322,7 +271,7 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm):
) )
class IPAddressBulkEditForm(NetBoxModelBulkEditForm): class IPAddressBulkEditForm(PrimaryModelBulkEditForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
@@ -354,12 +303,6 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
label=_('DNS name') label=_('DNS name')
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = IPAddress model = IPAddress
fieldsets = ( fieldsets = (
@@ -371,7 +314,7 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm):
) )
class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm): class FHRPGroupBulkEditForm(PrimaryModelBulkEditForm):
protocol = forms.ChoiceField( protocol = forms.ChoiceField(
label=_('Protocol'), label=_('Protocol'),
choices=add_blank_choice(FHRPGroupProtocolChoices), choices=add_blank_choice(FHRPGroupProtocolChoices),
@@ -397,12 +340,6 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm):
max_length=100, max_length=100,
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = FHRPGroup model = FHRPGroup
fieldsets = ( fieldsets = (
@@ -412,12 +349,7 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm):
nullable_fields = ('auth_type', 'auth_key', 'name', 'description', 'comments') nullable_fields = ('auth_type', 'auth_key', 'name', 'description', 'comments')
class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): class VLANGroupBulkEditForm(OrganizationalModelBulkEditForm):
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
scope_type = ContentTypeChoiceField( scope_type = ContentTypeChoiceField(
queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES), queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
widget=HTMXSelect(method='post', attrs={'hx-select': '#form_fields'}), widget=HTMXSelect(method='post', attrs={'hx-select': '#form_fields'}),
@@ -464,7 +396,7 @@ class VLANGroupBulkEditForm(NetBoxModelBulkEditForm):
pass pass
class VLANBulkEditForm(NetBoxModelBulkEditForm): class VLANBulkEditForm(PrimaryModelBulkEditForm):
region = DynamicModelChoiceField( region = DynamicModelChoiceField(
label=_('Region'), label=_('Region'),
queryset=Region.objects.all(), queryset=Region.objects.all(),
@@ -507,11 +439,6 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm):
queryset=Role.objects.all(), queryset=Role.objects.all(),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
qinq_role = forms.ChoiceField( qinq_role = forms.ChoiceField(
label=_('Q-in-Q role'), label=_('Q-in-Q role'),
choices=add_blank_choice(VLANQinQRoleChoices), choices=add_blank_choice(VLANQinQRoleChoices),
@@ -525,7 +452,6 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm):
'qinq_role': VLANQinQRoleChoices.ROLE_SERVICE, 'qinq_role': VLANQinQRoleChoices.ROLE_SERVICE,
} }
) )
comments = CommentField()
model = VLAN model = VLAN
fieldsets = ( fieldsets = (
@@ -538,13 +464,7 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm):
) )
class VLANTranslationPolicyBulkEditForm(NetBoxModelBulkEditForm): class VLANTranslationPolicyBulkEditForm(PrimaryModelBulkEditForm):
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
model = VLANTranslationPolicy model = VLANTranslationPolicy
fieldsets = ( fieldsets = (
FieldSet('description'), FieldSet('description'),
@@ -568,7 +488,7 @@ class VLANTranslationRuleBulkEditForm(NetBoxModelBulkEditForm):
fields = ('policy', 'local_vid', 'remote_vid') fields = ('policy', 'local_vid', 'remote_vid')
class ServiceTemplateBulkEditForm(NetBoxModelBulkEditForm): class ServiceTemplateBulkEditForm(PrimaryModelBulkEditForm):
protocol = forms.ChoiceField( protocol = forms.ChoiceField(
label=_('Protocol'), label=_('Protocol'),
choices=add_blank_choice(ServiceProtocolChoices), choices=add_blank_choice(ServiceProtocolChoices),
@@ -582,12 +502,6 @@ class ServiceTemplateBulkEditForm(NetBoxModelBulkEditForm):
), ),
required=False required=False
) )
description = forms.CharField(
label=_('Description'),
max_length=200,
required=False
)
comments = CommentField()
model = ServiceTemplate model = ServiceTemplate
fieldsets = ( fieldsets = (

View File

@@ -7,7 +7,7 @@ from dcim.forms.mixins import ScopedImportForm
from ipam.choices import * from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from ipam.models import * from ipam.models import *
from netbox.forms import NetBoxModelImportForm from netbox.forms import NetBoxModelImportForm, OrganizationalModelImportForm, PrimaryModelImportForm
from tenancy.models import Tenant from tenancy.models import Tenant
from utilities.forms.fields import ( from utilities.forms.fields import (
CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelMultipleChoiceField, SlugField, CSVChoiceField, CSVContentTypeField, CSVModelChoiceField, CSVModelMultipleChoiceField, SlugField,
@@ -36,7 +36,7 @@ __all__ = (
) )
class VRFImportForm(NetBoxModelImportForm): class VRFImportForm(PrimaryModelImportForm):
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
label=_('Tenant'), label=_('Tenant'),
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@@ -60,12 +60,12 @@ class VRFImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = VRF model = VRF
fields = ( fields = (
'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'comments', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'owner',
'tags', 'comments', 'tags',
) )
class RouteTargetImportForm(NetBoxModelImportForm): class RouteTargetImportForm(PrimaryModelImportForm):
tenant = CSVModelChoiceField( tenant = CSVModelChoiceField(
label=_('Tenant'), label=_('Tenant'),
queryset=Tenant.objects.all(), queryset=Tenant.objects.all(),
@@ -76,18 +76,18 @@ class RouteTargetImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = RouteTarget model = RouteTarget
fields = ('name', 'tenant', 'description', 'comments', 'tags') fields = ('name', 'tenant', 'description', 'owner', 'comments', 'tags')
class RIRImportForm(NetBoxModelImportForm): class RIRImportForm(OrganizationalModelImportForm):
slug = SlugField() slug = SlugField()
class Meta: class Meta:
model = RIR model = RIR
fields = ('name', 'slug', 'is_private', 'description', 'tags') fields = ('name', 'slug', 'is_private', 'description', 'owner', 'tags')
class AggregateImportForm(NetBoxModelImportForm): class AggregateImportForm(PrimaryModelImportForm):
rir = CSVModelChoiceField( rir = CSVModelChoiceField(
label=_('RIR'), label=_('RIR'),
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
@@ -104,10 +104,10 @@ class AggregateImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = Aggregate model = Aggregate
fields = ('prefix', 'rir', 'tenant', 'date_added', 'description', 'comments', 'tags') fields = ('prefix', 'rir', 'tenant', 'date_added', 'description', 'owner', 'comments', 'tags')
class ASNRangeImportForm(NetBoxModelImportForm): class ASNRangeImportForm(OrganizationalModelImportForm):
rir = CSVModelChoiceField( rir = CSVModelChoiceField(
label=_('RIR'), label=_('RIR'),
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
@@ -124,10 +124,10 @@ class ASNRangeImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ASNRange model = ASNRange
fields = ('name', 'slug', 'rir', 'start', 'end', 'tenant', 'description', 'tags') fields = ('name', 'slug', 'rir', 'start', 'end', 'tenant', 'description', 'owner', 'tags')
class ASNImportForm(NetBoxModelImportForm): class ASNImportForm(PrimaryModelImportForm):
rir = CSVModelChoiceField( rir = CSVModelChoiceField(
label=_('RIR'), label=_('RIR'),
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
@@ -144,18 +144,17 @@ class ASNImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ASN model = ASN
fields = ('asn', 'rir', 'tenant', 'description', 'comments', 'tags') fields = ('asn', 'rir', 'tenant', 'description', 'owner', 'comments', 'tags')
class RoleImportForm(NetBoxModelImportForm): class RoleImportForm(OrganizationalModelImportForm):
slug = SlugField()
class Meta: class Meta:
model = Role model = Role
fields = ('name', 'slug', 'weight', 'description', 'tags') fields = ('name', 'slug', 'weight', 'description', 'owner', 'tags')
class PrefixImportForm(ScopedImportForm, NetBoxModelImportForm): class PrefixImportForm(ScopedImportForm, PrimaryModelImportForm):
vrf = CSVModelChoiceField( vrf = CSVModelChoiceField(
label=_('VRF'), label=_('VRF'),
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
@@ -208,7 +207,7 @@ class PrefixImportForm(ScopedImportForm, NetBoxModelImportForm):
model = Prefix model = Prefix
fields = ( fields = (
'prefix', 'vrf', 'tenant', 'vlan_group', 'vlan_site', 'vlan', 'status', 'role', 'scope_type', 'scope_id', 'prefix', 'vrf', 'tenant', 'vlan_group', 'vlan_site', 'vlan', 'status', 'role', 'scope_type', 'scope_id',
'is_pool', 'mark_utilized', 'description', 'comments', 'tags', 'is_pool', 'mark_utilized', 'description', 'owner', 'comments', 'tags',
) )
labels = { labels = {
'scope_id': _('Scope ID'), 'scope_id': _('Scope ID'),
@@ -244,7 +243,7 @@ class PrefixImportForm(ScopedImportForm, NetBoxModelImportForm):
self.fields['vlan'].queryset = queryset self.fields['vlan'].queryset = queryset
class IPRangeImportForm(NetBoxModelImportForm): class IPRangeImportForm(PrimaryModelImportForm):
vrf = CSVModelChoiceField( vrf = CSVModelChoiceField(
label=_('VRF'), label=_('VRF'),
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
@@ -276,11 +275,11 @@ class IPRangeImportForm(NetBoxModelImportForm):
model = IPRange model = IPRange
fields = ( fields = (
'start_address', 'end_address', 'vrf', 'tenant', 'status', 'role', 'mark_populated', 'mark_utilized', 'start_address', 'end_address', 'vrf', 'tenant', 'status', 'role', 'mark_populated', 'mark_utilized',
'description', 'comments', 'tags', 'description', 'owner', 'comments', 'tags',
) )
class IPAddressImportForm(NetBoxModelImportForm): class IPAddressImportForm(PrimaryModelImportForm):
vrf = CSVModelChoiceField( vrf = CSVModelChoiceField(
label=_('VRF'), label=_('VRF'),
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
@@ -349,7 +348,7 @@ class IPAddressImportForm(NetBoxModelImportForm):
model = IPAddress model = IPAddress
fields = [ fields = [
'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface', 'fhrp_group', 'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface', 'fhrp_group',
'is_primary', 'is_oob', 'dns_name', 'description', 'comments', 'tags', 'is_primary', 'is_oob', 'dns_name', 'description', 'owner', 'comments', 'tags',
] ]
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):
@@ -428,7 +427,7 @@ class IPAddressImportForm(NetBoxModelImportForm):
return ipaddress return ipaddress
class FHRPGroupImportForm(NetBoxModelImportForm): class FHRPGroupImportForm(PrimaryModelImportForm):
protocol = CSVChoiceField( protocol = CSVChoiceField(
label=_('Protocol'), label=_('Protocol'),
choices=FHRPGroupProtocolChoices choices=FHRPGroupProtocolChoices
@@ -441,11 +440,10 @@ class FHRPGroupImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = FHRPGroup model = FHRPGroup
fields = ('protocol', 'group_id', 'auth_type', 'auth_key', 'name', 'description', 'comments', 'tags') fields = ('protocol', 'group_id', 'auth_type', 'auth_key', 'name', 'description', 'owner', 'comments', 'tags')
class VLANGroupImportForm(NetBoxModelImportForm): class VLANGroupImportForm(OrganizationalModelImportForm):
slug = SlugField()
scope_type = CSVContentTypeField( scope_type = CSVContentTypeField(
queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES), queryset=ContentType.objects.filter(model__in=VLANGROUP_SCOPE_TYPES),
required=False, required=False,
@@ -464,13 +462,13 @@ class VLANGroupImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = VLANGroup model = VLANGroup
fields = ('name', 'slug', 'scope_type', 'scope_id', 'vid_ranges', 'tenant', 'description', 'tags') fields = ('name', 'slug', 'scope_type', 'scope_id', 'vid_ranges', 'tenant', 'description', 'owner', 'tags')
labels = { labels = {
'scope_id': 'Scope ID', 'scope_id': 'Scope ID',
} }
class VLANImportForm(NetBoxModelImportForm): class VLANImportForm(PrimaryModelImportForm):
site = CSVModelChoiceField( site = CSVModelChoiceField(
label=_('Site'), label=_('Site'),
queryset=Site.objects.all(), queryset=Site.objects.all(),
@@ -522,15 +520,15 @@ class VLANImportForm(NetBoxModelImportForm):
model = VLAN model = VLAN
fields = ( fields = (
'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'qinq_role', 'qinq_svlan', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'qinq_role', 'qinq_svlan',
'comments', 'tags', 'owner', 'comments', 'tags',
) )
class VLANTranslationPolicyImportForm(NetBoxModelImportForm): class VLANTranslationPolicyImportForm(PrimaryModelImportForm):
class Meta: class Meta:
model = VLANTranslationPolicy model = VLANTranslationPolicy
fields = ('name', 'description', 'tags') fields = ('name', 'description', 'owner', 'comments', 'tags')
class VLANTranslationRuleImportForm(NetBoxModelImportForm): class VLANTranslationRuleImportForm(NetBoxModelImportForm):
@@ -546,7 +544,7 @@ class VLANTranslationRuleImportForm(NetBoxModelImportForm):
fields = ('policy', 'local_vid', 'remote_vid') fields = ('policy', 'local_vid', 'remote_vid')
class ServiceTemplateImportForm(NetBoxModelImportForm): class ServiceTemplateImportForm(PrimaryModelImportForm):
protocol = CSVChoiceField( protocol = CSVChoiceField(
label=_('Protocol'), label=_('Protocol'),
choices=ServiceProtocolChoices, choices=ServiceProtocolChoices,
@@ -555,10 +553,10 @@ class ServiceTemplateImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = ServiceTemplate model = ServiceTemplate
fields = ('name', 'protocol', 'ports', 'description', 'comments', 'tags') fields = ('name', 'protocol', 'ports', 'description', 'owner', 'comments', 'tags')
class ServiceImportForm(NetBoxModelImportForm): class ServiceImportForm(PrimaryModelImportForm):
parent_object_type = CSVContentTypeField( parent_object_type = CSVContentTypeField(
queryset=ContentType.objects.filter(SERVICE_ASSIGNMENT_MODELS), queryset=ContentType.objects.filter(SERVICE_ASSIGNMENT_MODELS),
required=True, required=True,
@@ -590,7 +588,7 @@ class ServiceImportForm(NetBoxModelImportForm):
class Meta: class Meta:
model = Service model = Service
fields = ( fields = (
'ipaddresses', 'name', 'protocol', 'ports', 'description', 'comments', 'tags', 'ipaddresses', 'name', 'protocol', 'ports', 'description', 'owner', 'comments', 'tags',
) )
def __init__(self, data=None, *args, **kwargs): def __init__(self, data=None, *args, **kwargs):

View File

@@ -5,7 +5,7 @@ from dcim.models import Location, Rack, Region, Site, SiteGroup, Device
from ipam.choices import * from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from ipam.models import * from ipam.models import *
from netbox.forms import NetBoxModelFilterSetForm from netbox.forms import NetBoxModelFilterSetForm, OrganizationalModelFilterSetForm, PrimaryModelFilterSetForm
from tenancy.forms import ContactModelFilterForm, TenancyFilterForm from tenancy.forms import ContactModelFilterForm, TenancyFilterForm
from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, add_blank_choice from utilities.forms import BOOLEAN_WITH_BLANK_CHOICES, add_blank_choice
from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField from utilities.forms.fields import DynamicModelChoiceField, DynamicModelMultipleChoiceField, TagFilterField
@@ -42,10 +42,10 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([
]) ])
class VRFFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class VRFFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = VRF model = VRF
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('import_target_id', 'export_target_id', name=_('Route Targets')), FieldSet('import_target_id', 'export_target_id', name=_('Route Targets')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
) )
@@ -62,10 +62,10 @@ class VRFFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class RouteTargetFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class RouteTargetFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = RouteTarget model = RouteTarget
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('importing_vrf_id', 'exporting_vrf_id', name=_('VRF')), FieldSet('importing_vrf_id', 'exporting_vrf_id', name=_('VRF')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
) )
@@ -82,8 +82,12 @@ class RouteTargetFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class RIRFilterForm(NetBoxModelFilterSetForm): class RIRFilterForm(OrganizationalModelFilterSetForm):
model = RIR model = RIR
fieldsets = (
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('is_private', name=_('RIR')),
)
is_private = forms.NullBooleanField( is_private = forms.NullBooleanField(
required=False, required=False,
label=_('Private'), label=_('Private'),
@@ -94,10 +98,10 @@ class RIRFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm): class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = Aggregate model = Aggregate
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('family', 'rir_id', name=_('Attributes')), FieldSet('family', 'rir_id', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
@@ -115,10 +119,10 @@ class AggregateFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModel
tag = TagFilterField(model) tag = TagFilterField(model)
class ASNRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class ASNRangeFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
model = ASNRange model = ASNRange
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('rir_id', 'start', 'end', name=_('Range')), FieldSet('rir_id', 'start', 'end', name=_('Range')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
) )
@@ -138,10 +142,10 @@ class ASNRangeFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class ASNFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = ASN model = ASN
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('rir_id', 'site_group_id', 'site_id', name=_('Assignment')), FieldSet('rir_id', 'site_group_id', 'site_id', name=_('Assignment')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
) )
@@ -163,15 +167,18 @@ class ASNFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class RoleFilterForm(NetBoxModelFilterSetForm): class RoleFilterForm(OrganizationalModelFilterSetForm):
model = Role model = Role
fieldsets = (
FieldSet('q', 'filter_id', 'tag', 'owner_id'),
)
tag = TagFilterField(model) tag = TagFilterField(model)
class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm, ): class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = Prefix model = Prefix
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet( FieldSet(
'within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized', 'within_include', 'family', 'status', 'role_id', 'mask_length', 'is_pool', 'mark_utilized',
name=_('Addressing') name=_('Addressing')
@@ -274,10 +281,10 @@ class PrefixFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFil
tag = TagFilterField(model) tag = TagFilterField(model)
class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm): class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = IPRange model = IPRange
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_populated', 'mark_utilized', name=_('Attributes')), FieldSet('family', 'vrf_id', 'status', 'role_id', 'mark_populated', 'mark_utilized', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),
@@ -321,10 +328,10 @@ class IPRangeFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFi
tag = TagFilterField(model) tag = TagFilterField(model)
class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModelFilterSetForm): class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, PrimaryModelFilterSetForm):
model = IPAddress model = IPAddress
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet( FieldSet(
'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface', 'dns_name', 'parent', 'family', 'status', 'role', 'mask_length', 'assigned_to_interface', 'dns_name',
name=_('Attributes') name=_('Attributes')
@@ -399,10 +406,10 @@ class IPAddressFilterForm(ContactModelFilterForm, TenancyFilterForm, NetBoxModel
tag = TagFilterField(model) tag = TagFilterField(model)
class FHRPGroupFilterForm(NetBoxModelFilterSetForm): class FHRPGroupFilterForm(PrimaryModelFilterSetForm):
model = FHRPGroup model = FHRPGroup
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', 'protocol', 'group_id', name=_('Attributes')), FieldSet('name', 'protocol', 'group_id', name=_('Attributes')),
FieldSet('auth_type', 'auth_key', name=_('Authentication')), FieldSet('auth_type', 'auth_key', name=_('Authentication')),
) )
@@ -432,9 +439,9 @@ class FHRPGroupFilterForm(NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class VLANGroupFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class VLANGroupFilterForm(TenancyFilterForm, OrganizationalModelFilterSetForm):
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region', 'site_group', 'site', 'location', 'rack', name=_('Location')), FieldSet('region', 'site_group', 'site', 'location', 'rack', name=_('Location')),
FieldSet('cluster_group', 'cluster', name=_('Cluster')), FieldSet('cluster_group', 'cluster', name=_('Cluster')),
FieldSet('contains_vid', name=_('VLANs')), FieldSet('contains_vid', name=_('VLANs')),
@@ -485,10 +492,10 @@ class VLANGroupFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class VLANTranslationPolicyFilterForm(NetBoxModelFilterSetForm): class VLANTranslationPolicyFilterForm(PrimaryModelFilterSetForm):
model = VLANTranslationPolicy model = VLANTranslationPolicy
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('name', name=_('Attributes')), FieldSet('name', name=_('Attributes')),
) )
name = forms.CharField( name = forms.CharField(
@@ -522,10 +529,10 @@ class VLANTranslationRuleFilterForm(NetBoxModelFilterSetForm):
) )
class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm): class VLANFilterForm(TenancyFilterForm, PrimaryModelFilterSetForm):
model = VLAN model = VLAN
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')), FieldSet('region_id', 'site_group_id', 'site_id', name=_('Location')),
FieldSet('group_id', 'status', 'role_id', 'vid', 'l2vpn_id', name=_('Attributes')), FieldSet('group_id', 'status', 'role_id', 'vid', 'l2vpn_id', name=_('Attributes')),
FieldSet('qinq_role', 'qinq_svlan_id', name=_('Q-in-Q/802.1ad')), FieldSet('qinq_role', 'qinq_svlan_id', name=_('Q-in-Q/802.1ad')),
@@ -594,10 +601,10 @@ class VLANFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
tag = TagFilterField(model) tag = TagFilterField(model)
class ServiceTemplateFilterForm(NetBoxModelFilterSetForm): class ServiceTemplateFilterForm(PrimaryModelFilterSetForm):
model = ServiceTemplate model = ServiceTemplate
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('protocol', 'port', name=_('Attributes')), FieldSet('protocol', 'port', name=_('Attributes')),
) )
protocol = forms.ChoiceField( protocol = forms.ChoiceField(
@@ -615,7 +622,7 @@ class ServiceTemplateFilterForm(NetBoxModelFilterSetForm):
class ServiceFilterForm(ContactModelFilterForm, ServiceTemplateFilterForm): class ServiceFilterForm(ContactModelFilterForm, ServiceTemplateFilterForm):
model = Service model = Service
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag', 'owner_id'),
FieldSet('protocol', 'port', name=_('Attributes')), FieldSet('protocol', 'port', name=_('Attributes')),
FieldSet('device_id', 'virtual_machine_id', 'fhrpgroup_id', name=_('Assignment')), FieldSet('device_id', 'virtual_machine_id', 'fhrpgroup_id', name=_('Assignment')),
FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')), FieldSet('contact', 'contact_role', 'contact_group', name=_('Contacts')),

View File

@@ -9,13 +9,13 @@ from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from ipam.formfields import IPNetworkFormField from ipam.formfields import IPNetworkFormField
from ipam.models import * from ipam.models import *
from netbox.forms import NetBoxModelForm from netbox.forms import NetBoxModelForm, OrganizationalModelForm, PrimaryModelForm
from tenancy.forms import TenancyForm from tenancy.forms import TenancyForm
from utilities.exceptions import PermissionsViolation from utilities.exceptions import PermissionsViolation
from utilities.forms import add_blank_choice from utilities.forms import add_blank_choice
from utilities.forms.fields import ( from utilities.forms.fields import (
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField,
NumericRangeArrayField, SlugField NumericRangeArrayField,
) )
from utilities.forms.rendering import FieldSet, InlineFields, ObjectAttribute, TabbedGroups from utilities.forms.rendering import FieldSet, InlineFields, ObjectAttribute, TabbedGroups
from utilities.forms.utils import get_field_value from utilities.forms.utils import get_field_value
@@ -49,7 +49,7 @@ __all__ = (
) )
class VRFForm(TenancyForm, NetBoxModelForm): class VRFForm(TenancyForm, PrimaryModelForm):
import_targets = DynamicModelMultipleChoiceField( import_targets = DynamicModelMultipleChoiceField(
label=_('Import targets'), label=_('Import targets'),
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
@@ -60,7 +60,6 @@ class VRFForm(TenancyForm, NetBoxModelForm):
queryset=RouteTarget.objects.all(), queryset=RouteTarget.objects.all(),
required=False required=False
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('name', 'rd', 'enforce_unique', 'description', 'tags', name=_('VRF')), FieldSet('name', 'rd', 'enforce_unique', 'description', 'tags', name=_('VRF')),
@@ -72,30 +71,27 @@ class VRFForm(TenancyForm, NetBoxModelForm):
model = VRF model = VRF
fields = [ fields = [
'name', 'rd', 'enforce_unique', 'import_targets', 'export_targets', 'tenant_group', 'tenant', 'description', 'name', 'rd', 'enforce_unique', 'import_targets', 'export_targets', 'tenant_group', 'tenant', 'description',
'comments', 'tags', 'owner', 'comments', 'tags',
] ]
labels = { labels = {
'rd': "RD", 'rd': "RD",
} }
class RouteTargetForm(TenancyForm, NetBoxModelForm): class RouteTargetForm(TenancyForm, PrimaryModelForm):
fieldsets = ( fieldsets = (
FieldSet('name', 'description', 'tags', name=_('Route Target')), FieldSet('name', 'description', 'tags', name=_('Route Target')),
FieldSet('tenant_group', 'tenant', name=_('Tenancy')), FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
) )
comments = CommentField()
class Meta: class Meta:
model = RouteTarget model = RouteTarget
fields = [ fields = [
'name', 'tenant_group', 'tenant', 'description', 'comments', 'tags', 'name', 'tenant_group', 'tenant', 'description', 'owner', 'comments', 'tags',
] ]
class RIRForm(NetBoxModelForm): class RIRForm(OrganizationalModelForm):
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'is_private', 'description', 'tags', name=_('RIR')), FieldSet('name', 'slug', 'is_private', 'description', 'tags', name=_('RIR')),
) )
@@ -103,17 +99,16 @@ class RIRForm(NetBoxModelForm):
class Meta: class Meta:
model = RIR model = RIR
fields = [ fields = [
'name', 'slug', 'is_private', 'description', 'tags', 'name', 'slug', 'is_private', 'description', 'owner', 'tags',
] ]
class AggregateForm(TenancyForm, NetBoxModelForm): class AggregateForm(TenancyForm, PrimaryModelForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
label=_('RIR'), label=_('RIR'),
quick_add=True quick_add=True
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('prefix', 'rir', 'date_added', 'description', 'tags', name=_('Aggregate')), FieldSet('prefix', 'rir', 'date_added', 'description', 'tags', name=_('Aggregate')),
@@ -123,20 +118,19 @@ class AggregateForm(TenancyForm, NetBoxModelForm):
class Meta: class Meta:
model = Aggregate model = Aggregate
fields = [ fields = [
'prefix', 'rir', 'date_added', 'tenant_group', 'tenant', 'description', 'comments', 'tags', 'prefix', 'rir', 'date_added', 'tenant_group', 'tenant', 'description', 'owner', 'comments', 'tags',
] ]
widgets = { widgets = {
'date_added': DatePicker(), 'date_added': DatePicker(),
} }
class ASNRangeForm(TenancyForm, NetBoxModelForm): class ASNRangeForm(TenancyForm, OrganizationalModelForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
label=_('RIR'), label=_('RIR'),
quick_add=True quick_add=True
) )
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'rir', 'start', 'end', 'description', 'tags', name=_('ASN Range')), FieldSet('name', 'slug', 'rir', 'start', 'end', 'description', 'tags', name=_('ASN Range')),
FieldSet('tenant_group', 'tenant', name=_('Tenancy')), FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
@@ -145,11 +139,11 @@ class ASNRangeForm(TenancyForm, NetBoxModelForm):
class Meta: class Meta:
model = ASNRange model = ASNRange
fields = [ fields = [
'name', 'slug', 'rir', 'start', 'end', 'tenant_group', 'tenant', 'description', 'tags' 'name', 'slug', 'rir', 'start', 'end', 'tenant_group', 'tenant', 'owner', 'description', 'tags'
] ]
class ASNForm(TenancyForm, NetBoxModelForm): class ASNForm(TenancyForm, PrimaryModelForm):
rir = DynamicModelChoiceField( rir = DynamicModelChoiceField(
queryset=RIR.objects.all(), queryset=RIR.objects.all(),
label=_('RIR'), label=_('RIR'),
@@ -160,7 +154,6 @@ class ASNForm(TenancyForm, NetBoxModelForm):
label=_('Sites'), label=_('Sites'),
required=False required=False
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('asn', 'rir', 'sites', 'description', 'tags', name=_('ASN')), FieldSet('asn', 'rir', 'sites', 'description', 'tags', name=_('ASN')),
@@ -170,7 +163,7 @@ class ASNForm(TenancyForm, NetBoxModelForm):
class Meta: class Meta:
model = ASN model = ASN
fields = [ fields = [
'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'comments', 'tags' 'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'owner', 'comments', 'tags'
] ]
widgets = { widgets = {
'date_added': DatePicker(), 'date_added': DatePicker(),
@@ -188,9 +181,7 @@ class ASNForm(TenancyForm, NetBoxModelForm):
return instance return instance
class RoleForm(NetBoxModelForm): class RoleForm(OrganizationalModelForm):
slug = SlugField()
fieldsets = ( fieldsets = (
FieldSet('name', 'slug', 'weight', 'description', 'tags', name=_('Role')), FieldSet('name', 'slug', 'weight', 'description', 'tags', name=_('Role')),
) )
@@ -198,11 +189,11 @@ class RoleForm(NetBoxModelForm):
class Meta: class Meta:
model = Role model = Role
fields = [ fields = [
'name', 'slug', 'weight', 'description', 'tags', 'name', 'slug', 'weight', 'description', 'owner', 'tags',
] ]
class PrefixForm(TenancyForm, ScopedForm, NetBoxModelForm): class PrefixForm(TenancyForm, ScopedForm, PrimaryModelForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
@@ -223,7 +214,6 @@ class PrefixForm(TenancyForm, ScopedForm, NetBoxModelForm):
required=False, required=False,
quick_add=True quick_add=True
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -238,7 +228,7 @@ class PrefixForm(TenancyForm, ScopedForm, NetBoxModelForm):
model = Prefix model = Prefix
fields = [ fields = [
'prefix', 'vrf', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'scope_type', 'tenant_group', 'prefix', 'vrf', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'scope_type', 'tenant_group',
'tenant', 'description', 'comments', 'tags', 'tenant', 'description', 'owner', 'comments', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -250,7 +240,7 @@ class PrefixForm(TenancyForm, ScopedForm, NetBoxModelForm):
self.fields['vlan'].widget.attrs.pop('data-dynamic-params', None) self.fields['vlan'].widget.attrs.pop('data-dynamic-params', None)
class IPRangeForm(TenancyForm, NetBoxModelForm): class IPRangeForm(TenancyForm, PrimaryModelForm):
vrf = DynamicModelChoiceField( vrf = DynamicModelChoiceField(
queryset=VRF.objects.all(), queryset=VRF.objects.all(),
required=False, required=False,
@@ -262,7 +252,6 @@ class IPRangeForm(TenancyForm, NetBoxModelForm):
required=False, required=False,
quick_add=True quick_add=True
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -276,11 +265,11 @@ class IPRangeForm(TenancyForm, NetBoxModelForm):
model = IPRange model = IPRange
fields = [ fields = [
'vrf', 'start_address', 'end_address', 'status', 'role', 'tenant_group', 'tenant', 'mark_populated', 'vrf', 'start_address', 'end_address', 'status', 'role', 'tenant_group', 'tenant', 'mark_populated',
'mark_utilized', 'description', 'comments', 'tags', 'mark_utilized', 'description', 'owner', 'comments', 'tags',
] ]
class IPAddressForm(TenancyForm, NetBoxModelForm): class IPAddressForm(TenancyForm, PrimaryModelForm):
interface = DynamicModelChoiceField( interface = DynamicModelChoiceField(
queryset=Interface.objects.all(), queryset=Interface.objects.all(),
required=False, required=False,
@@ -324,7 +313,6 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
required=False, required=False,
label=_('Make this the out-of-band IP for the device') label=_('Make this the out-of-band IP for the device')
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('address', 'status', 'role', 'vrf', 'dns_name', 'description', 'tags', name=_('IP Address')), FieldSet('address', 'status', 'role', 'vrf', 'dns_name', 'description', 'tags', name=_('IP Address')),
@@ -344,7 +332,7 @@ class IPAddressForm(TenancyForm, NetBoxModelForm):
model = IPAddress model = IPAddress
fields = [ fields = [
'address', 'vrf', 'status', 'role', 'dns_name', 'primary_for_parent', 'oob_for_parent', 'nat_inside', 'address', 'vrf', 'status', 'role', 'dns_name', 'primary_for_parent', 'oob_for_parent', 'nat_inside',
'tenant_group', 'tenant', 'description', 'comments', 'tags', 'tenant_group', 'tenant', 'description', 'owner', 'comments', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -494,7 +482,7 @@ class IPAddressAssignForm(forms.Form):
) )
class FHRPGroupForm(NetBoxModelForm): class FHRPGroupForm(PrimaryModelForm):
# Optionally create a new IPAddress along with the FHRPGroup # Optionally create a new IPAddress along with the FHRPGroup
ip_vrf = DynamicModelChoiceField( ip_vrf = DynamicModelChoiceField(
@@ -511,7 +499,6 @@ class FHRPGroupForm(NetBoxModelForm):
required=False, required=False,
label=_('Status') label=_('Status')
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('protocol', 'group_id', 'name', 'description', 'tags', name=_('FHRP Group')), FieldSet('protocol', 'group_id', 'name', 'description', 'tags', name=_('FHRP Group')),
@@ -523,7 +510,7 @@ class FHRPGroupForm(NetBoxModelForm):
model = FHRPGroup model = FHRPGroup
fields = ( fields = (
'protocol', 'group_id', 'auth_type', 'auth_key', 'name', 'ip_vrf', 'ip_address', 'ip_status', 'description', 'protocol', 'group_id', 'auth_type', 'auth_key', 'name', 'ip_vrf', 'ip_address', 'ip_status', 'description',
'comments', 'tags', 'owner', 'comments', 'tags',
) )
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
@@ -599,8 +586,7 @@ class FHRPGroupAssignmentForm(forms.ModelForm):
return group return group
class VLANGroupForm(TenancyForm, NetBoxModelForm): class VLANGroupForm(TenancyForm, OrganizationalModelForm):
slug = SlugField()
vid_ranges = NumericRangeArrayField( vid_ranges = NumericRangeArrayField(
label=_('VLAN IDs') label=_('VLAN IDs')
) )
@@ -628,7 +614,7 @@ class VLANGroupForm(TenancyForm, NetBoxModelForm):
class Meta: class Meta:
model = VLANGroup model = VLANGroup
fields = [ fields = [
'name', 'slug', 'description', 'vid_ranges', 'scope_type', 'tenant_group', 'tenant', 'tags', 'name', 'slug', 'description', 'vid_ranges', 'scope_type', 'tenant_group', 'tenant', 'owner', 'tags',
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@@ -662,7 +648,7 @@ class VLANGroupForm(TenancyForm, NetBoxModelForm):
self.instance.scope = self.cleaned_data.get('scope') self.instance.scope = self.cleaned_data.get('scope')
class VLANForm(TenancyForm, NetBoxModelForm): class VLANForm(TenancyForm, PrimaryModelForm):
group = DynamicModelChoiceField( group = DynamicModelChoiceField(
queryset=VLANGroup.objects.all(), queryset=VLANGroup.objects.all(),
required=False, required=False,
@@ -698,17 +684,16 @@ class VLANForm(TenancyForm, NetBoxModelForm):
'qinq_role': VLANQinQRoleChoices.ROLE_SERVICE, 'qinq_role': VLANQinQRoleChoices.ROLE_SERVICE,
} }
) )
comments = CommentField()
class Meta: class Meta:
model = VLAN model = VLAN
fields = [ fields = [
'site', 'group', 'vid', 'name', 'status', 'role', 'tenant_group', 'tenant', 'qinq_role', 'qinq_svlan', 'site', 'group', 'vid', 'name', 'status', 'role', 'tenant_group', 'tenant', 'qinq_role', 'qinq_svlan',
'description', 'comments', 'tags', 'description', 'owner', 'comments', 'tags',
] ]
class VLANTranslationPolicyForm(NetBoxModelForm): class VLANTranslationPolicyForm(PrimaryModelForm):
fieldsets = ( fieldsets = (
FieldSet('name', 'description', 'tags', name=_('VLAN Translation Policy')), FieldSet('name', 'description', 'tags', name=_('VLAN Translation Policy')),
@@ -717,7 +702,7 @@ class VLANTranslationPolicyForm(NetBoxModelForm):
class Meta: class Meta:
model = VLANTranslationPolicy model = VLANTranslationPolicy
fields = [ fields = [
'name', 'description', 'tags', 'name', 'description', 'owner', 'tags',
] ]
@@ -739,7 +724,7 @@ class VLANTranslationRuleForm(NetBoxModelForm):
] ]
class ServiceTemplateForm(NetBoxModelForm): class ServiceTemplateForm(PrimaryModelForm):
ports = NumericArrayField( ports = NumericArrayField(
label=_('Ports'), label=_('Ports'),
base_field=forms.IntegerField( base_field=forms.IntegerField(
@@ -748,7 +733,6 @@ class ServiceTemplateForm(NetBoxModelForm):
), ),
help_text=_("Comma-separated list of one or more port numbers. A range may be specified using a hyphen.") help_text=_("Comma-separated list of one or more port numbers. A range may be specified using a hyphen.")
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet('name', 'protocol', 'ports', 'description', 'tags', name=_('Application Service Template')), FieldSet('name', 'protocol', 'ports', 'description', 'tags', name=_('Application Service Template')),
@@ -756,10 +740,10 @@ class ServiceTemplateForm(NetBoxModelForm):
class Meta: class Meta:
model = ServiceTemplate model = ServiceTemplate
fields = ('name', 'protocol', 'ports', 'description', 'comments', 'tags') fields = ('name', 'protocol', 'ports', 'description', 'owner', 'comments', 'tags')
class ServiceForm(NetBoxModelForm): class ServiceForm(PrimaryModelForm):
parent_object_type = ContentTypeChoiceField( parent_object_type = ContentTypeChoiceField(
queryset=ContentType.objects.filter(SERVICE_ASSIGNMENT_MODELS), queryset=ContentType.objects.filter(SERVICE_ASSIGNMENT_MODELS),
widget=HTMXSelect(), widget=HTMXSelect(),
@@ -786,7 +770,6 @@ class ServiceForm(NetBoxModelForm):
required=False, required=False,
label=_('IP Addresses'), label=_('IP Addresses'),
) )
comments = CommentField()
fieldsets = ( fieldsets = (
FieldSet( FieldSet(
@@ -799,7 +782,7 @@ class ServiceForm(NetBoxModelForm):
class Meta: class Meta:
model = Service model = Service
fields = [ fields = [
'name', 'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags', 'name', 'protocol', 'ports', 'ipaddresses', 'description', 'owner', 'comments', 'tags',
'parent_object_type', 'parent_object_type',
] ]

View File

@@ -8,7 +8,7 @@ from dcim.graphql.types import SiteType
from extras.graphql.mixins import ContactsMixin from extras.graphql.mixins import ContactsMixin
from ipam import models from ipam import models
from netbox.graphql.scalars import BigInt from netbox.graphql.scalars import BigInt
from netbox.graphql.types import BaseObjectType, NetBoxObjectType, OrganizationalObjectType from netbox.graphql.types import BaseObjectType, NetBoxObjectType, OrganizationalObjectType, PrimaryObjectType
from .filters import * from .filters import *
from .mixins import IPAddressesMixin from .mixins import IPAddressesMixin
@@ -74,7 +74,7 @@ class BaseIPAddressFamilyType:
filters=ASNFilter, filters=ASNFilter,
pagination=True pagination=True
) )
class ASNType(NetBoxObjectType, ContactsMixin): class ASNType(ContactsMixin, PrimaryObjectType):
asn: BigInt asn: BigInt
rir: Annotated["RIRType", strawberry.lazy('ipam.graphql.types')] | None rir: Annotated["RIRType", strawberry.lazy('ipam.graphql.types')] | None
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -89,7 +89,7 @@ class ASNType(NetBoxObjectType, ContactsMixin):
filters=ASNRangeFilter, filters=ASNRangeFilter,
pagination=True pagination=True
) )
class ASNRangeType(NetBoxObjectType): class ASNRangeType(OrganizationalObjectType):
start: BigInt start: BigInt
end: BigInt end: BigInt
rir: Annotated["RIRType", strawberry.lazy('ipam.graphql.types')] | None rir: Annotated["RIRType", strawberry.lazy('ipam.graphql.types')] | None
@@ -102,7 +102,7 @@ class ASNRangeType(NetBoxObjectType):
filters=AggregateFilter, filters=AggregateFilter,
pagination=True pagination=True
) )
class AggregateType(NetBoxObjectType, ContactsMixin, BaseIPAddressFamilyType): class AggregateType(ContactsMixin, BaseIPAddressFamilyType, PrimaryObjectType):
prefix: str prefix: str
rir: Annotated["RIRType", strawberry.lazy('ipam.graphql.types')] | None rir: Annotated["RIRType", strawberry.lazy('ipam.graphql.types')] | None
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -114,8 +114,7 @@ class AggregateType(NetBoxObjectType, ContactsMixin, BaseIPAddressFamilyType):
filters=FHRPGroupFilter, filters=FHRPGroupFilter,
pagination=True pagination=True
) )
class FHRPGroupType(NetBoxObjectType, IPAddressesMixin): class FHRPGroupType(IPAddressesMixin, PrimaryObjectType):
fhrpgroupassignment_set: List[Annotated["FHRPGroupAssignmentType", strawberry.lazy('ipam.graphql.types')]] fhrpgroupassignment_set: List[Annotated["FHRPGroupAssignmentType", strawberry.lazy('ipam.graphql.types')]]
@@ -142,7 +141,7 @@ class FHRPGroupAssignmentType(BaseObjectType):
filters=IPAddressFilter, filters=IPAddressFilter,
pagination=True pagination=True
) )
class IPAddressType(NetBoxObjectType, ContactsMixin, BaseIPAddressFamilyType): class IPAddressType(ContactsMixin, BaseIPAddressFamilyType, PrimaryObjectType):
address: str address: str
vrf: Annotated["VRFType", strawberry.lazy('ipam.graphql.types')] | None vrf: Annotated["VRFType", strawberry.lazy('ipam.graphql.types')] | None
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -167,7 +166,7 @@ class IPAddressType(NetBoxObjectType, ContactsMixin, BaseIPAddressFamilyType):
filters=IPRangeFilter, filters=IPRangeFilter,
pagination=True pagination=True
) )
class IPRangeType(NetBoxObjectType, ContactsMixin): class IPRangeType(ContactsMixin, PrimaryObjectType):
start_address: str start_address: str
end_address: str end_address: str
vrf: Annotated["VRFType", strawberry.lazy('ipam.graphql.types')] | None vrf: Annotated["VRFType", strawberry.lazy('ipam.graphql.types')] | None
@@ -181,7 +180,7 @@ class IPRangeType(NetBoxObjectType, ContactsMixin):
filters=PrefixFilter, filters=PrefixFilter,
pagination=True pagination=True
) )
class PrefixType(NetBoxObjectType, ContactsMixin, BaseIPAddressFamilyType): class PrefixType(ContactsMixin, BaseIPAddressFamilyType, PrimaryObjectType):
prefix: str prefix: str
vrf: Annotated["VRFType", strawberry.lazy('ipam.graphql.types')] | None vrf: Annotated["VRFType", strawberry.lazy('ipam.graphql.types')] | None
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -230,7 +229,7 @@ class RoleType(OrganizationalObjectType):
filters=RouteTargetFilter, filters=RouteTargetFilter,
pagination=True pagination=True
) )
class RouteTargetType(NetBoxObjectType): class RouteTargetType(PrimaryObjectType):
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
importing_l2vpns: List[Annotated["L2VPNType", strawberry.lazy('vpn.graphql.types')]] importing_l2vpns: List[Annotated["L2VPNType", strawberry.lazy('vpn.graphql.types')]]
@@ -245,7 +244,7 @@ class RouteTargetType(NetBoxObjectType):
filters=ServiceFilter, filters=ServiceFilter,
pagination=True pagination=True
) )
class ServiceType(NetBoxObjectType, ContactsMixin): class ServiceType(ContactsMixin, PrimaryObjectType):
ports: List[int] ports: List[int]
ipaddresses: List[Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')]] ipaddresses: List[Annotated["IPAddressType", strawberry.lazy('ipam.graphql.types')]]
@@ -264,7 +263,7 @@ class ServiceType(NetBoxObjectType, ContactsMixin):
filters=ServiceTemplateFilter, filters=ServiceTemplateFilter,
pagination=True pagination=True
) )
class ServiceTemplateType(NetBoxObjectType): class ServiceTemplateType(PrimaryObjectType):
ports: List[int] ports: List[int]
@@ -274,7 +273,7 @@ class ServiceTemplateType(NetBoxObjectType):
filters=VLANFilter, filters=VLANFilter,
pagination=True pagination=True
) )
class VLANType(NetBoxObjectType): class VLANType(PrimaryObjectType):
site: Annotated["SiteType", strawberry.lazy('ipam.graphql.types')] | None site: Annotated["SiteType", strawberry.lazy('ipam.graphql.types')] | None
group: Annotated["VLANGroupType", strawberry.lazy('ipam.graphql.types')] | None group: Annotated["VLANGroupType", strawberry.lazy('ipam.graphql.types')] | None
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
@@ -323,7 +322,7 @@ class VLANGroupType(OrganizationalObjectType):
filters=VLANTranslationPolicyFilter, filters=VLANTranslationPolicyFilter,
pagination=True pagination=True
) )
class VLANTranslationPolicyType(NetBoxObjectType): class VLANTranslationPolicyType(PrimaryObjectType):
rules: List[Annotated["VLANTranslationRuleType", strawberry.lazy('ipam.graphql.types')]] rules: List[Annotated["VLANTranslationRuleType", strawberry.lazy('ipam.graphql.types')]]
@@ -346,7 +345,7 @@ class VLANTranslationRuleType(NetBoxObjectType):
filters=VRFFilter, filters=VRFFilter,
pagination=True pagination=True
) )
class VRFType(NetBoxObjectType): class VRFType(PrimaryObjectType):
tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None tenant: Annotated["TenantType", strawberry.lazy('tenancy.graphql.types')] | None
interfaces: List[Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')]] interfaces: List[Annotated["InterfaceType", strawberry.lazy('dcim.graphql.types')]]

View File

@@ -0,0 +1,124 @@
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('ipam', '0082_add_prefix_network_containment_indexes'),
('users', '0015_owner'),
]
operations = [
migrations.AddField(
model_name='aggregate',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='asn',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='asnrange',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='fhrpgroup',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='ipaddress',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='iprange',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='prefix',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='rir',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='role',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='routetarget',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='service',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='servicetemplate',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='vlan',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='vlangroup',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='vlantranslationpolicy',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
migrations.AddField(
model_name='vrf',
name='owner',
field=models.ForeignKey(
blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='users.owner'
),
),
]

View File

@@ -2,7 +2,7 @@ import django_tables2 as tables
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from ipam.models import * from ipam.models import *
from netbox.tables import NetBoxTable, columns from netbox.tables import OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import TenancyColumnsMixin from tenancy.tables import TenancyColumnsMixin
__all__ = ( __all__ = (
@@ -11,7 +11,7 @@ __all__ = (
) )
class ASNRangeTable(TenancyColumnsMixin, NetBoxTable): class ASNRangeTable(TenancyColumnsMixin, OrganizationalModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -27,7 +27,7 @@ class ASNRangeTable(TenancyColumnsMixin, NetBoxTable):
verbose_name=_('ASNs') verbose_name=_('ASNs')
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = ASNRange model = ASNRange
fields = ( fields = (
'pk', 'name', 'slug', 'rir', 'start', 'end', 'asn_count', 'tenant', 'tenant_group', 'description', 'tags', 'pk', 'name', 'slug', 'rir', 'start', 'end', 'asn_count', 'tenant', 'tenant_group', 'description', 'tags',
@@ -36,7 +36,7 @@ class ASNRangeTable(TenancyColumnsMixin, NetBoxTable):
default_columns = ('pk', 'name', 'rir', 'start', 'end', 'tenant', 'asn_count', 'description') default_columns = ('pk', 'name', 'rir', 'start', 'end', 'tenant', 'asn_count', 'description')
class ASNTable(TenancyColumnsMixin, NetBoxTable): class ASNTable(TenancyColumnsMixin, PrimaryModelTable):
asn = tables.Column( asn = tables.Column(
verbose_name=_('ASN'), verbose_name=_('ASN'),
linkify=True linkify=True
@@ -65,14 +65,11 @@ class ASNTable(TenancyColumnsMixin, NetBoxTable):
linkify_item=True, linkify_item=True,
verbose_name=_('Sites') verbose_name=_('Sites')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:asn_list' url_name='ipam:asn_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = ASN model = ASN
fields = ( fields = (
'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description', 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description',

View File

@@ -1,8 +1,8 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from ipam.models import * from ipam.models import *
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, PrimaryModelTable, columns
__all__ = ( __all__ = (
'FHRPGroupTable', 'FHRPGroupTable',
@@ -17,7 +17,7 @@ IPADDRESSES = """
""" """
class FHRPGroupTable(NetBoxTable): class FHRPGroupTable(PrimaryModelTable):
group_id = tables.Column( group_id = tables.Column(
verbose_name=_('Group ID'), verbose_name=_('Group ID'),
linkify=True linkify=True
@@ -30,9 +30,6 @@ class FHRPGroupTable(NetBoxTable):
member_count = tables.Column( member_count = tables.Column(
verbose_name=_('Members') verbose_name=_('Members')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:fhrpgroup_list' url_name='ipam:fhrpgroup_list'
) )
@@ -40,7 +37,7 @@ class FHRPGroupTable(NetBoxTable):
def value_ip_addresses(self, value): def value_ip_addresses(self, value):
return ",".join([str(obj.address) for obj in value.all()]) return ",".join([str(obj.address) for obj in value.all()])
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = FHRPGroup model = FHRPGroup
fields = ( fields = (
'pk', 'group_id', 'protocol', 'name', 'auth_type', 'auth_key', 'description', 'comments', 'ip_addresses', 'pk', 'group_id', 'protocol', 'name', 'auth_type', 'auth_key', 'description', 'comments', 'ip_addresses',

View File

@@ -1,10 +1,10 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from django.utils.translation import gettext_lazy as _
from django_tables2.utils import Accessor from django_tables2.utils import Accessor
from ipam.models import * from ipam.models import *
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import TenancyColumnsMixin, TenantColumn from tenancy.tables import TenancyColumnsMixin, TenantColumn
from .template_code import * from .template_code import *
@@ -27,7 +27,7 @@ AVAILABLE_LABEL = mark_safe('<span class="badge text-bg-success">Available</span
# RIRs # RIRs
# #
class RIRTable(NetBoxTable): class RIRTable(OrganizationalModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -45,7 +45,7 @@ class RIRTable(NetBoxTable):
url_name='ipam:rir_list' url_name='ipam:rir_list'
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = RIR model = RIR
fields = ( fields = (
'pk', 'id', 'name', 'slug', 'is_private', 'aggregate_count', 'description', 'tags', 'created', 'pk', 'id', 'name', 'slug', 'is_private', 'aggregate_count', 'description', 'tags', 'created',
@@ -58,7 +58,7 @@ class RIRTable(NetBoxTable):
# Aggregates # Aggregates
# #
class AggregateTable(TenancyColumnsMixin, NetBoxTable): class AggregateTable(TenancyColumnsMixin, PrimaryModelTable):
prefix = tables.Column( prefix = tables.Column(
linkify=True, linkify=True,
verbose_name=_('Aggregate'), verbose_name=_('Aggregate'),
@@ -79,9 +79,6 @@ class AggregateTable(TenancyColumnsMixin, NetBoxTable):
accessor='get_utilization', accessor='get_utilization',
orderable=False orderable=False
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:aggregate_list' url_name='ipam:aggregate_list'
) )
@@ -89,7 +86,7 @@ class AggregateTable(TenancyColumnsMixin, NetBoxTable):
extra_buttons=AGGREGATE_COPY_BUTTON extra_buttons=AGGREGATE_COPY_BUTTON
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Aggregate model = Aggregate
fields = ( fields = (
'pk', 'id', 'prefix', 'rir', 'tenant', 'tenant_group', 'child_count', 'utilization', 'date_added', 'pk', 'id', 'prefix', 'rir', 'tenant', 'tenant_group', 'child_count', 'utilization', 'date_added',
@@ -102,7 +99,7 @@ class AggregateTable(TenancyColumnsMixin, NetBoxTable):
# Roles # Roles
# #
class RoleTable(NetBoxTable): class RoleTable(OrganizationalModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -126,7 +123,7 @@ class RoleTable(NetBoxTable):
url_name='ipam:role_list' url_name='ipam:role_list'
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = Role model = Role
fields = ( fields = (
'pk', 'id', 'name', 'slug', 'prefix_count', 'iprange_count', 'vlan_count', 'description', 'weight', 'tags', 'pk', 'id', 'name', 'slug', 'prefix_count', 'iprange_count', 'vlan_count', 'description', 'weight', 'tags',
@@ -154,7 +151,7 @@ class PrefixUtilizationColumn(columns.UtilizationColumn):
""" """
class PrefixTable(TenancyColumnsMixin, NetBoxTable): class PrefixTable(TenancyColumnsMixin, PrimaryModelTable):
prefix = columns.TemplateColumn( prefix = columns.TemplateColumn(
verbose_name=_('Prefix'), verbose_name=_('Prefix'),
template_code=PREFIX_LINK_WITH_DEPTH, template_code=PREFIX_LINK_WITH_DEPTH,
@@ -223,9 +220,6 @@ class PrefixTable(TenancyColumnsMixin, NetBoxTable):
accessor='get_utilization', accessor='get_utilization',
orderable=False orderable=False
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:prefix_list' url_name='ipam:prefix_list'
) )
@@ -233,7 +227,7 @@ class PrefixTable(TenancyColumnsMixin, NetBoxTable):
extra_buttons=PREFIX_COPY_BUTTON extra_buttons=PREFIX_COPY_BUTTON
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Prefix model = Prefix
fields = ( fields = (
'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'tenant_group', 'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'tenant_group',
@@ -252,7 +246,7 @@ class PrefixTable(TenancyColumnsMixin, NetBoxTable):
# #
# IP ranges # IP ranges
# #
class IPRangeTable(TenancyColumnsMixin, NetBoxTable): class IPRangeTable(TenancyColumnsMixin, PrimaryModelTable):
start_address = tables.Column( start_address = tables.Column(
verbose_name=_('Start address'), verbose_name=_('Start address'),
linkify=True linkify=True
@@ -282,14 +276,11 @@ class IPRangeTable(TenancyColumnsMixin, NetBoxTable):
accessor='utilization', accessor='utilization',
orderable=False orderable=False
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:iprange_list' url_name='ipam:iprange_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = IPRange model = IPRange
fields = ( fields = (
'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'tenant_group',
@@ -308,7 +299,7 @@ class IPRangeTable(TenancyColumnsMixin, NetBoxTable):
# IPAddresses # IPAddresses
# #
class IPAddressTable(TenancyColumnsMixin, NetBoxTable): class IPAddressTable(TenancyColumnsMixin, PrimaryModelTable):
address = tables.TemplateColumn( address = tables.TemplateColumn(
template_code=IPADDRESS_LINK, template_code=IPADDRESS_LINK,
verbose_name=_('IP Address') verbose_name=_('IP Address')
@@ -351,9 +342,6 @@ class IPAddressTable(TenancyColumnsMixin, NetBoxTable):
verbose_name=_('Assigned'), verbose_name=_('Assigned'),
false_mark=None false_mark=None
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:ipaddress_list' url_name='ipam:ipaddress_list'
) )
@@ -361,7 +349,7 @@ class IPAddressTable(TenancyColumnsMixin, NetBoxTable):
extra_buttons=IPADDRESS_COPY_BUTTON extra_buttons=IPADDRESS_COPY_BUTTON
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = IPAddress model = IPAddress
fields = ( fields = (
'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'nat_inside', 'nat_outside', 'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'nat_inside', 'nat_outside',

View File

@@ -1,8 +1,8 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from ipam.models import * from ipam.models import *
from netbox.tables import NetBoxTable, columns from netbox.tables import PrimaryModelTable, columns
__all__ = ( __all__ = (
'ServiceTable', 'ServiceTable',
@@ -10,7 +10,7 @@ __all__ = (
) )
class ServiceTemplateTable(NetBoxTable): class ServiceTemplateTable(PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -20,14 +20,11 @@ class ServiceTemplateTable(NetBoxTable):
accessor=tables.A('port_list'), accessor=tables.A('port_list'),
order_by=tables.A('ports'), order_by=tables.A('ports'),
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:servicetemplate_list' url_name='ipam:servicetemplate_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = ServiceTemplate model = ServiceTemplate
fields = ( fields = (
'pk', 'id', 'name', 'protocol', 'ports', 'description', 'comments', 'tags', 'created', 'last_updated', 'pk', 'id', 'name', 'protocol', 'ports', 'description', 'comments', 'tags', 'created', 'last_updated',
@@ -35,7 +32,7 @@ class ServiceTemplateTable(NetBoxTable):
default_columns = ('pk', 'name', 'protocol', 'ports', 'description') default_columns = ('pk', 'name', 'protocol', 'ports', 'description')
class ServiceTable(NetBoxTable): class ServiceTable(PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -50,14 +47,11 @@ class ServiceTable(NetBoxTable):
accessor=tables.A('port_list'), accessor=tables.A('port_list'),
order_by=tables.A('ports'), order_by=tables.A('ports'),
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:service_list' url_name='ipam:service_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = Service model = Service
fields = ( fields = (
'pk', 'id', 'name', 'parent', 'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags', 'pk', 'id', 'name', 'parent', 'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags',

View File

@@ -5,7 +5,7 @@ from django_tables2.utils import Accessor
from dcim.models import Interface from dcim.models import Interface
from ipam.models import * from ipam.models import *
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, OrganizationalModelTable, PrimaryModelTable, columns
from tenancy.tables import TenancyColumnsMixin, TenantColumn from tenancy.tables import TenancyColumnsMixin, TenantColumn
from virtualization.models import VMInterface from virtualization.models import VMInterface
from .template_code import * from .template_code import *
@@ -28,7 +28,7 @@ AVAILABLE_LABEL = mark_safe('<span class="badge text-bg-success">Available</span
# VLAN groups # VLAN groups
# #
class VLANGroupTable(TenancyColumnsMixin, NetBoxTable): class VLANGroupTable(TenancyColumnsMixin, OrganizationalModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -62,7 +62,7 @@ class VLANGroupTable(TenancyColumnsMixin, NetBoxTable):
extra_buttons=VLANGROUP_BUTTONS extra_buttons=VLANGROUP_BUTTONS
) )
class Meta(NetBoxTable.Meta): class Meta(OrganizationalModelTable.Meta):
model = VLANGroup model = VLANGroup
fields = ( fields = (
'pk', 'id', 'name', 'scope_type', 'scope', 'vid_ranges_list', 'vlan_count', 'slug', 'description', 'pk', 'id', 'name', 'scope_type', 'scope', 'vid_ranges_list', 'vlan_count', 'slug', 'description',
@@ -77,7 +77,7 @@ class VLANGroupTable(TenancyColumnsMixin, NetBoxTable):
# VLANs # VLANs
# #
class VLANTable(TenancyColumnsMixin, NetBoxTable): class VLANTable(TenancyColumnsMixin, PrimaryModelTable):
vid = tables.TemplateColumn( vid = tables.TemplateColumn(
template_code=VLAN_LINK, template_code=VLAN_LINK,
verbose_name=_('VID') verbose_name=_('VID')
@@ -120,14 +120,11 @@ class VLANTable(TenancyColumnsMixin, NetBoxTable):
orderable=False, orderable=False,
verbose_name=_('Prefixes') verbose_name=_('Prefixes')
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:vlan_list' url_name='ipam:vlan_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = VLAN model = VLAN
fields = ( fields = (
'pk', 'id', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'tenant_group', 'status', 'role', 'pk', 'id', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'tenant_group', 'status', 'role',
@@ -229,7 +226,7 @@ class InterfaceVLANTable(NetBoxTable):
# VLAN Translation # VLAN Translation
# #
class VLANTranslationPolicyTable(NetBoxTable): class VLANTranslationPolicyTable(PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -246,7 +243,7 @@ class VLANTranslationPolicyTable(NetBoxTable):
url_name='ipam:vlantranslationpolicy_list' url_name='ipam:vlantranslationpolicy_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = VLANTranslationPolicy model = VLANTranslationPolicy
fields = ( fields = (
'pk', 'id', 'name', 'rule_count', 'description', 'tags', 'created', 'last_updated', 'pk', 'id', 'name', 'rule_count', 'description', 'tags', 'created', 'last_updated',

View File

@@ -1,8 +1,8 @@
from django.utils.translation import gettext_lazy as _
import django_tables2 as tables import django_tables2 as tables
from django.utils.translation import gettext_lazy as _
from ipam.models import * from ipam.models import *
from netbox.tables import NetBoxTable, columns from netbox.tables import PrimaryModelTable, columns
from tenancy.tables import TenancyColumnsMixin from tenancy.tables import TenancyColumnsMixin
__all__ = ( __all__ = (
@@ -21,7 +21,7 @@ VRF_TARGETS = """
# VRFs # VRFs
# #
class VRFTable(TenancyColumnsMixin, NetBoxTable): class VRFTable(TenancyColumnsMixin, PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
@@ -43,14 +43,11 @@ class VRFTable(TenancyColumnsMixin, NetBoxTable):
template_code=VRF_TARGETS, template_code=VRF_TARGETS,
orderable=False orderable=False
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:vrf_list' url_name='ipam:vrf_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = VRF model = VRF
fields = ( fields = (
'pk', 'id', 'name', 'rd', 'tenant', 'tenant_group', 'enforce_unique', 'import_targets', 'export_targets', 'pk', 'id', 'name', 'rd', 'tenant', 'tenant_group', 'enforce_unique', 'import_targets', 'export_targets',
@@ -63,19 +60,16 @@ class VRFTable(TenancyColumnsMixin, NetBoxTable):
# Route targets # Route targets
# #
class RouteTargetTable(TenancyColumnsMixin, NetBoxTable): class RouteTargetTable(TenancyColumnsMixin, PrimaryModelTable):
name = tables.Column( name = tables.Column(
verbose_name=_('Name'), verbose_name=_('Name'),
linkify=True linkify=True
) )
comments = columns.MarkdownColumn(
verbose_name=_('Comments'),
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='ipam:routetarget_list' url_name='ipam:routetarget_list'
) )
class Meta(NetBoxTable.Meta): class Meta(PrimaryModelTable.Meta):
model = RouteTarget model = RouteTarget
fields = ( fields = (
'pk', 'id', 'name', 'tenant', 'tenant_group', 'description', 'comments', 'tags', 'created', 'last_updated', 'pk', 'id', 'name', 'tenant', 'tenant_group', 'description', 'comments', 'tags', 'created', 'last_updated',

View File

@@ -1,33 +1,6 @@
from rest_framework import serializers
from .base import * from .base import *
from .features import * from .features import *
from .generic import * from .generic import *
from .nested import * from .nested import *
from .models import *
from .bulk import *
#
# Base model serializers
#
class NetBoxModelSerializer(
ChangeLogMessageSerializer,
TaggableModelSerializer,
CustomFieldModelSerializer,
ValidatedModelSerializer
):
"""
Adds support for custom fields and tags.
"""
pass
class NestedGroupModelSerializer(NetBoxModelSerializer):
"""
Extends PrimaryModelSerializer to include MPTT support.
"""
_depth = serializers.IntegerField(source='level', read_only=True)
class BulkOperationSerializer(ChangeLogMessageSerializer):
id = serializers.IntegerField()

View File

@@ -0,0 +1,11 @@
from rest_framework import serializers
from .features import ChangeLogMessageSerializer
__all__ = (
'BulkOperationSerializer',
)
class BulkOperationSerializer(ChangeLogMessageSerializer):
id = serializers.IntegerField()

View File

@@ -2,11 +2,13 @@ from rest_framework import serializers
from rest_framework.fields import CreateOnlyDefault from rest_framework.fields import CreateOnlyDefault
from extras.api.customfields import CustomFieldsDataField, CustomFieldDefaultValues from extras.api.customfields import CustomFieldsDataField, CustomFieldDefaultValues
from .base import ValidatedModelSerializer
from .nested import NestedTagSerializer from .nested import NestedTagSerializer
__all__ = ( __all__ = (
'ChangeLogMessageSerializer', 'ChangeLogMessageSerializer',
'CustomFieldModelSerializer', 'CustomFieldModelSerializer',
'NetBoxModelSerializer',
'TaggableModelSerializer', 'TaggableModelSerializer',
) )
@@ -76,3 +78,15 @@ class ChangeLogMessageSerializer(serializers.Serializer):
if self.instance is not None: if self.instance is not None:
self.instance._changelog_message = self.validated_data.get('changelog_message') self.instance._changelog_message = self.validated_data.get('changelog_message')
return super().save(**kwargs) return super().save(**kwargs)
class NetBoxModelSerializer(
ChangeLogMessageSerializer,
TaggableModelSerializer,
CustomFieldModelSerializer,
ValidatedModelSerializer
):
"""
Adds support for custom fields and tags.
"""
pass

View File

@@ -0,0 +1,31 @@
from rest_framework import serializers
from .features import NetBoxModelSerializer
from users.api.serializers_.mixins import OwnerMixin
__all__ = (
'NestedGroupModelSerializer',
'OrganizationalModelSerializer',
'PrimaryModelSerializer',
)
class PrimaryModelSerializer(OwnerMixin, NetBoxModelSerializer):
"""
Base serializer class for models inheriting from PrimaryModel.
"""
pass
class NestedGroupModelSerializer(OwnerMixin, NetBoxModelSerializer):
"""
Base serializer class for models inheriting from NestedGroupModel.
"""
_depth = serializers.IntegerField(source='level', read_only=True)
class OrganizationalModelSerializer(OwnerMixin, NetBoxModelSerializer):
"""
Base serializer class for models inheriting from OrganizationalModel.
"""
pass

View File

@@ -14,6 +14,7 @@ from core.models import ObjectChange
from extras.choices import CustomFieldFilterLogicChoices from extras.choices import CustomFieldFilterLogicChoices
from extras.filters import TagFilter, TagIDFilter from extras.filters import TagFilter, TagIDFilter
from extras.models import CustomField, SavedFilter from extras.models import CustomField, SavedFilter
from users.filterset_mixins import OwnerFilterMixin
from utilities.constants import ( from utilities.constants import (
FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP, FILTER_CHAR_BASED_LOOKUP_MAP, FILTER_NEGATION_LOOKUP_MAP, FILTER_TREENODE_NEGATION_LOOKUP_MAP,
FILTER_NUMERIC_BASED_LOOKUP_MAP FILTER_NUMERIC_BASED_LOOKUP_MAP
@@ -25,8 +26,10 @@ __all__ = (
'AttributeFiltersMixin', 'AttributeFiltersMixin',
'BaseFilterSet', 'BaseFilterSet',
'ChangeLoggedModelFilterSet', 'ChangeLoggedModelFilterSet',
'NestedGroupModelFilterSet',
'NetBoxModelFilterSet', 'NetBoxModelFilterSet',
'OrganizationalModelFilterSet', 'OrganizationalModelFilterSet',
'PrimaryModelFilterSet',
) )
STANDARD_LOOKUPS = ( STANDARD_LOOKUPS = (
@@ -328,9 +331,16 @@ class NetBoxModelFilterSet(ChangeLoggedModelFilterSet):
return queryset return queryset
class OrganizationalModelFilterSet(NetBoxModelFilterSet): class PrimaryModelFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
""" """
A base class for adding the search method to models which only expose the `name` and `slug` fields Base filterset for models inheriting from PrimaryModel.
"""
pass
class OrganizationalModelFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
"""
Base filterset for models inheriting from OrganizationalModel.
""" """
def search(self, queryset, name, value): def search(self, queryset, name, value):
if not value.strip(): if not value.strip():
@@ -342,9 +352,9 @@ class OrganizationalModelFilterSet(NetBoxModelFilterSet):
) )
class NestedGroupModelFilterSet(NetBoxModelFilterSet): class NestedGroupModelFilterSet(OwnerFilterMixin, NetBoxModelFilterSet):
""" """
A base FilterSet for models that inherit from NestedGroupModel Base filterset for models inheriting from NestedGroupModel.
""" """
def search(self, queryset, name, value): def search(self, queryset, name, value):
if value.strip(): if value.strip():

View File

@@ -1,57 +1,5 @@
import re from .model_forms import *
from .bulk_import import *
from django import forms from .bulk_edit import *
from django.utils.translation import gettext_lazy as _ from .filtersets import *
from .search import *
from netbox.search import LookupTypes
from netbox.search.backends import search_backend
from .base import *
LOOKUP_CHOICES = (
('', _('Partial match')),
(LookupTypes.EXACT, _('Exact match')),
(LookupTypes.STARTSWITH, _('Starts with')),
(LookupTypes.ENDSWITH, _('Ends with')),
(LookupTypes.REGEX, _('Regex')),
)
class SearchForm(forms.Form):
q = forms.CharField(
label=_('Search'),
widget=forms.TextInput(
attrs={
'hx-get': '',
'hx-target': '#object_list',
'hx-trigger': 'keyup[target.value.length >= 3] changed delay:500ms',
}
)
)
obj_types = forms.MultipleChoiceField(
choices=[],
required=False,
label=_('Object type(s)')
)
lookup = forms.ChoiceField(
choices=LOOKUP_CHOICES,
initial=LookupTypes.PARTIAL,
required=False,
label=_('Lookup')
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['obj_types'].choices = search_backend.get_object_types()
def clean(self):
# Validate regular expressions
if self.cleaned_data['lookup'] == LookupTypes.REGEX:
try:
re.compile(self.cleaned_data['q'])
except re.error as e:
raise forms.ValidationError({
'q': f'Invalid regular expression: {e}'
})

View File

@@ -1,178 +0,0 @@
import json
from django import forms
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from core.models import ObjectType
from extras.choices import *
from extras.models import CustomField, Tag
from utilities.forms import BulkEditForm, CSVModelForm
from utilities.forms.fields import CSVModelMultipleChoiceField, DynamicModelMultipleChoiceField
from utilities.forms.mixins import CheckLastUpdatedMixin
from .mixins import ChangelogMessageMixin, CustomFieldsMixin, SavedFiltersMixin, TagsMixin
__all__ = (
'NetBoxModelForm',
'NetBoxModelImportForm',
'NetBoxModelBulkEditForm',
'NetBoxModelFilterSetForm',
)
class NetBoxModelForm(ChangelogMessageMixin, CheckLastUpdatedMixin, CustomFieldsMixin, TagsMixin, forms.ModelForm):
"""
Base form for creating & editing NetBox models. Extends Django's ModelForm to add support for custom fields.
Attributes:
fieldsets: An iterable of FieldSets which define a name and set of fields to display per section of
the rendered form (optional). If not defined, the all fields will be rendered as a single section.
"""
fieldsets = ()
def _get_content_type(self):
return ContentType.objects.get_for_model(self._meta.model)
def _get_form_field(self, customfield):
if self.instance.pk:
form_field = customfield.to_form_field(set_initial=False)
initial = self.instance.custom_field_data.get(customfield.name)
if customfield.type == CustomFieldTypeChoices.TYPE_JSON:
form_field.initial = json.dumps(initial)
else:
form_field.initial = initial
return form_field
return customfield.to_form_field()
def clean(self):
# Save custom field data on instance
for cf_name, customfield in self.custom_fields.items():
if cf_name not in self.fields:
# Custom fields may be absent when performing bulk updates via import
continue
key = cf_name[3:] # Strip "cf_" from field name
value = self.cleaned_data.get(cf_name)
# Convert "empty" values to null
if value in self.fields[cf_name].empty_values:
self.instance.custom_field_data[key] = None
else:
if customfield.type == CustomFieldTypeChoices.TYPE_JSON and type(value) is str:
value = json.loads(value)
self.instance.custom_field_data[key] = customfield.serialize(value)
return super().clean()
def _post_clean(self):
"""
Override BaseModelForm's _post_clean() to store many-to-many field values on the model instance.
"""
self.instance._m2m_values = {}
for field in self.instance._meta.local_many_to_many:
if field.name in self.cleaned_data:
self.instance._m2m_values[field.name] = list(self.cleaned_data[field.name])
return super()._post_clean()
class NetBoxModelImportForm(CSVModelForm, NetBoxModelForm):
"""
Base form for creating a NetBox objects from CSV data. Used for bulk importing.
"""
tags = CSVModelMultipleChoiceField(
label=_('Tags'),
queryset=Tag.objects.all(),
required=False,
to_field_name='slug',
help_text=_('Tag slugs separated by commas, encased with double quotes (e.g. "tag1,tag2,tag3")')
)
def _get_custom_fields(self, content_type):
return CustomField.objects.filter(
object_types=content_type,
ui_editable=CustomFieldUIEditableChoices.YES
)
def _get_form_field(self, customfield):
return customfield.to_form_field(for_csv_import=True)
class NetBoxModelBulkEditForm(ChangelogMessageMixin, CustomFieldsMixin, BulkEditForm):
"""
Base form for modifying multiple NetBox objects (of the same type) in bulk via the UI. Adds support for custom
fields and adding/removing tags.
Attributes:
fieldsets: An iterable of two-tuples which define a heading and field set to display per section of
the rendered form (optional). If not defined, the all fields will be rendered as a single section.
"""
fieldsets = None
pk = forms.ModelMultipleChoiceField(
queryset=None, # Set from self.model on init
widget=forms.MultipleHiddenInput
)
add_tags = DynamicModelMultipleChoiceField(
label=_('Add tags'),
queryset=Tag.objects.all(),
required=False
)
remove_tags = DynamicModelMultipleChoiceField(
label=_('Remove tags'),
queryset=Tag.objects.all(),
required=False
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['pk'].queryset = self.model.objects.all()
# Restrict tag fields by model
object_type = ObjectType.objects.get_for_model(self.model)
self.fields['add_tags'].widget.add_query_param('for_object_type_id', object_type.pk)
self.fields['remove_tags'].widget.add_query_param('for_object_type_id', object_type.pk)
self._extend_nullable_fields()
def _get_form_field(self, customfield):
return customfield.to_form_field(set_initial=False, enforce_required=False)
def _extend_nullable_fields(self):
nullable_custom_fields = [
name for name, customfield in self.custom_fields.items()
if (not customfield.required and customfield.ui_editable == CustomFieldUIEditableChoices.YES)
]
self.nullable_fields = (*self.nullable_fields, *nullable_custom_fields)
class NetBoxModelFilterSetForm(CustomFieldsMixin, SavedFiltersMixin, forms.Form):
"""
Base form for FilerSet forms. These are used to filter object lists in the NetBox UI. Note that the
corresponding FilterSet *must* provide a `q` filter.
Attributes:
model: The model class associated with the form
fieldsets: An iterable of two-tuples which define a heading and field set to display per section of
the rendered form (optional). If not defined, the all fields will be rendered as a single section.
selector_fields: An iterable of names of fields to display by default when rendering the form as
a selector widget
"""
q = forms.CharField(
required=False,
label=_('Search')
)
selector_fields = ('filter_id', 'q')
def _get_custom_fields(self, content_type):
return super()._get_custom_fields(content_type).exclude(
Q(filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED) |
Q(type=CustomFieldTypeChoices.TYPE_JSON)
)
def _get_form_field(self, customfield):
return customfield.to_form_field(set_initial=False, enforce_required=False, enforce_visibility=False)

Some files were not shown because too many files have changed in this diff Show More