mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Implemented tags for all primary models
This commit is contained in:
@ -1,13 +1,14 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework import serializers
|
||||
from taggit.models import Tag
|
||||
|
||||
from circuits.constants import CIRCUIT_STATUS_CHOICES
|
||||
from circuits.models import Provider, Circuit, CircuitTermination, CircuitType
|
||||
from dcim.api.serializers import NestedSiteSerializer, InterfaceSerializer
|
||||
from extras.api.customfields import CustomFieldModelSerializer
|
||||
from tenancy.api.serializers import NestedTenantSerializer
|
||||
from utilities.api import ChoiceFieldSerializer, ValidatedModelSerializer, WritableNestedSerializer
|
||||
from utilities.api import ChoiceFieldSerializer, TagField, ValidatedModelSerializer, WritableNestedSerializer
|
||||
|
||||
|
||||
#
|
||||
@ -15,11 +16,12 @@ from utilities.api import ChoiceFieldSerializer, ValidatedModelSerializer, Writa
|
||||
#
|
||||
|
||||
class ProviderSerializer(CustomFieldModelSerializer):
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Provider
|
||||
fields = [
|
||||
'id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments',
|
||||
'id', 'name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags',
|
||||
'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
|
||||
@ -60,12 +62,13 @@ class CircuitSerializer(CustomFieldModelSerializer):
|
||||
status = ChoiceFieldSerializer(choices=CIRCUIT_STATUS_CHOICES, required=False)
|
||||
type = NestedCircuitTypeSerializer()
|
||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Circuit
|
||||
fields = [
|
||||
'id', 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description',
|
||||
'comments', 'custom_fields', 'created', 'last_updated',
|
||||
'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
|
||||
|
||||
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Site, Device, Interface, Rack
|
||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||
@ -22,10 +23,11 @@ from .models import Circuit, CircuitTermination, CircuitType, Provider
|
||||
class ProviderForm(BootstrapMixin, CustomFieldForm):
|
||||
slug = SlugField()
|
||||
comments = CommentField()
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Provider
|
||||
fields = ['name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments']
|
||||
fields = ['name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments', 'tags']
|
||||
widgets = {
|
||||
'noc_contact': SmallTextarea(attrs={'rows': 5}),
|
||||
'admin_contact': SmallTextarea(attrs={'rows': 5}),
|
||||
@ -102,12 +104,13 @@ class CircuitTypeCSVForm(forms.ModelForm):
|
||||
|
||||
class CircuitForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
comments = CommentField()
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Circuit
|
||||
fields = [
|
||||
'cid', 'type', 'provider', 'status', 'install_date', 'commit_rate', 'description', 'tenant_group', 'tenant',
|
||||
'comments',
|
||||
'comments', 'tags',
|
||||
]
|
||||
help_texts = {
|
||||
'cid': "Unique circuit ID",
|
||||
|
@ -4,6 +4,7 @@ from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from dcim.constants import STATUS_CLASSES
|
||||
from dcim.fields import ASNField
|
||||
@ -56,6 +57,8 @@ class Provider(CreatedUpdatedModel, CustomFieldModel):
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = ['name', 'slug', 'asn', 'account', 'portal_url', 'noc_contact', 'admin_contact', 'comments']
|
||||
|
||||
class Meta:
|
||||
@ -166,6 +169,8 @@ class Circuit(CreatedUpdatedModel, CustomFieldModel):
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = [
|
||||
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
|
||||
]
|
||||
|
@ -784,8 +784,8 @@ class DeviceForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
class Meta:
|
||||
model = Device
|
||||
fields = [
|
||||
'name', 'device_role', 'tags', 'device_type', 'serial', 'asset_tag', 'site', 'rack', 'position', 'face',
|
||||
'status', 'platform', 'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant', 'comments',
|
||||
'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'site', 'rack', 'position', 'face',
|
||||
'status', 'platform', 'primary_ip4', 'primary_ip6', 'tenant_group', 'tenant', 'comments', 'tags',
|
||||
]
|
||||
help_texts = {
|
||||
'device_role': "The function this device serves",
|
||||
|
@ -5,6 +5,7 @@ from collections import OrderedDict
|
||||
from rest_framework import serializers
|
||||
from rest_framework.reverse import reverse
|
||||
from rest_framework.validators import UniqueTogetherValidator
|
||||
from taggit.models import Tag
|
||||
|
||||
from dcim.api.serializers import NestedDeviceSerializer, InterfaceSerializer, NestedSiteSerializer
|
||||
from dcim.models import Interface
|
||||
@ -14,7 +15,9 @@ from ipam.constants import (
|
||||
)
|
||||
from ipam.models import Aggregate, IPAddress, Prefix, RIR, Role, Service, VLAN, VLANGroup, VRF
|
||||
from tenancy.api.serializers import NestedTenantSerializer
|
||||
from utilities.api import ChoiceFieldSerializer, SerializedPKRelatedField, ValidatedModelSerializer, WritableNestedSerializer
|
||||
from utilities.api import (
|
||||
ChoiceFieldSerializer, SerializedPKRelatedField, TagField, ValidatedModelSerializer, WritableNestedSerializer,
|
||||
)
|
||||
from virtualization.api.serializers import NestedVirtualMachineSerializer
|
||||
|
||||
|
||||
@ -24,12 +27,13 @@ from virtualization.api.serializers import NestedVirtualMachineSerializer
|
||||
|
||||
class VRFSerializer(CustomFieldModelSerializer):
|
||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = VRF
|
||||
fields = [
|
||||
'id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'display_name', 'custom_fields', 'created',
|
||||
'last_updated',
|
||||
'id', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'tags', 'display_name', 'custom_fields',
|
||||
'created', 'last_updated',
|
||||
]
|
||||
|
||||
|
||||
@ -85,11 +89,13 @@ class NestedRIRSerializer(WritableNestedSerializer):
|
||||
|
||||
class AggregateSerializer(CustomFieldModelSerializer):
|
||||
rir = NestedRIRSerializer()
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Aggregate
|
||||
fields = [
|
||||
'id', 'family', 'prefix', 'rir', 'date_added', 'description', 'custom_fields', 'created', 'last_updated',
|
||||
'id', 'family', 'prefix', 'rir', 'date_added', 'description', 'tags', 'custom_fields', 'created',
|
||||
'last_updated',
|
||||
]
|
||||
read_only_fields = ['family']
|
||||
|
||||
@ -147,11 +153,12 @@ class VLANSerializer(CustomFieldModelSerializer):
|
||||
tenant = NestedTenantSerializer(required=False, allow_null=True)
|
||||
status = ChoiceFieldSerializer(choices=VLAN_STATUS_CHOICES, required=False)
|
||||
role = NestedRoleSerializer(required=False, allow_null=True)
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = VLAN
|
||||
fields = [
|
||||
'id', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'display_name',
|
||||
'id', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'tags', 'display_name',
|
||||
'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
validators = []
|
||||
@ -190,12 +197,13 @@ class PrefixSerializer(CustomFieldModelSerializer):
|
||||
vlan = NestedVLANSerializer(required=False, allow_null=True)
|
||||
status = ChoiceFieldSerializer(choices=PREFIX_STATUS_CHOICES, required=False)
|
||||
role = NestedRoleSerializer(required=False, allow_null=True)
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Prefix
|
||||
fields = [
|
||||
'id', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool', 'description',
|
||||
'custom_fields', 'created', 'last_updated',
|
||||
'tags', 'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
read_only_fields = ['family']
|
||||
|
||||
@ -252,12 +260,13 @@ class IPAddressSerializer(CustomFieldModelSerializer):
|
||||
status = ChoiceFieldSerializer(choices=IPADDRESS_STATUS_CHOICES, required=False)
|
||||
role = ChoiceFieldSerializer(choices=IPADDRESS_ROLE_CHOICES, required=False)
|
||||
interface = IPAddressInterfaceSerializer(required=False, allow_null=True)
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = IPAddress
|
||||
fields = [
|
||||
'id', 'family', 'address', 'vrf', 'tenant', 'status', 'role', 'interface', 'description', 'nat_inside',
|
||||
'nat_outside', 'custom_fields', 'created', 'last_updated',
|
||||
'nat_outside', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
read_only_fields = ['family']
|
||||
|
||||
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
||||
from django import forms
|
||||
from django.core.exceptions import MultipleObjectsReturned
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Site, Rack, Device, Interface
|
||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||
@ -32,10 +33,11 @@ IPADDRESS_MASK_LENGTH_CHOICES = add_blank_choice([(i, i) for i in range(1, 129)]
|
||||
#
|
||||
|
||||
class VRFForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = VRF
|
||||
fields = ['name', 'rd', 'enforce_unique', 'description', 'tenant_group', 'tenant']
|
||||
fields = ['name', 'rd', 'enforce_unique', 'description', 'tenant_group', 'tenant', 'tags']
|
||||
labels = {
|
||||
'rd': "RD",
|
||||
}
|
||||
@ -121,10 +123,11 @@ class RIRFilterForm(BootstrapMixin, forms.Form):
|
||||
#
|
||||
|
||||
class AggregateForm(BootstrapMixin, CustomFieldForm):
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Aggregate
|
||||
fields = ['prefix', 'rir', 'date_added', 'description']
|
||||
fields = ['prefix', 'rir', 'date_added', 'description', 'tags']
|
||||
help_texts = {
|
||||
'prefix': "IPv4 or IPv6 network",
|
||||
'rir': "Regional Internet Registry responsible for this prefix",
|
||||
@ -228,10 +231,14 @@ class PrefixForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
api_url='/api/ipam/vlans/?site_id={{site}}&group_id={{vlan_group}}', display_field='display_name'
|
||||
)
|
||||
)
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Prefix
|
||||
fields = ['prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'description', 'tenant_group', 'tenant']
|
||||
fields = [
|
||||
'prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'description', 'tenant_group', 'tenant',
|
||||
'tags',
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
@ -455,12 +462,13 @@ class IPAddressForm(BootstrapMixin, TenancyForm, ReturnURLForm, CustomFieldForm)
|
||||
)
|
||||
)
|
||||
primary_for_parent = forms.BooleanField(required=False, label='Make this the primary IP for the device/VM')
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = IPAddress
|
||||
fields = [
|
||||
'address', 'vrf', 'status', 'role', 'description', 'interface', 'primary_for_parent', 'nat_site',
|
||||
'nat_rack', 'nat_inside', 'tenant_group', 'tenant',
|
||||
'nat_rack', 'nat_inside', 'tenant_group', 'tenant', 'tags',
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -780,10 +788,11 @@ class VLANForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
api_url='/api/ipam/vlan-groups/?site_id={{site}}',
|
||||
)
|
||||
)
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = VLAN
|
||||
fields = ['site', 'group', 'vid', 'name', 'status', 'role', 'description', 'tenant_group', 'tenant']
|
||||
fields = ['site', 'group', 'vid', 'name', 'status', 'role', 'description', 'tenant_group', 'tenant', 'tags']
|
||||
help_texts = {
|
||||
'site': "Leave blank if this VLAN spans multiple sites",
|
||||
'group': "VLAN group (optional)",
|
||||
|
@ -10,6 +10,7 @@ from django.db.models import Q
|
||||
from django.db.models.expressions import RawSQL
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from dcim.models import Interface
|
||||
from extras.models import CustomFieldModel
|
||||
@ -56,6 +57,8 @@ class VRF(CreatedUpdatedModel, CustomFieldModel):
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = ['name', 'rd', 'tenant', 'enforce_unique', 'description']
|
||||
|
||||
class Meta:
|
||||
@ -155,6 +158,8 @@ class Aggregate(CreatedUpdatedModel, CustomFieldModel):
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = ['prefix', 'rir', 'date_added', 'description']
|
||||
|
||||
class Meta:
|
||||
@ -325,6 +330,7 @@ class Prefix(CreatedUpdatedModel, CustomFieldModel):
|
||||
)
|
||||
|
||||
objects = PrefixQuerySet.as_manager()
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = [
|
||||
'prefix', 'vrf', 'tenant', 'site', 'vlan_group', 'vlan_vid', 'status', 'role', 'is_pool', 'description',
|
||||
@ -564,6 +570,7 @@ class IPAddress(CreatedUpdatedModel, CustomFieldModel):
|
||||
)
|
||||
|
||||
objects = IPAddressManager()
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = [
|
||||
'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface_name', 'is_primary',
|
||||
@ -759,6 +766,8 @@ class VLAN(CreatedUpdatedModel, CustomFieldModel):
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = ['site', 'group_name', 'vid', 'name', 'tenant', 'status', 'role', 'description']
|
||||
|
||||
class Meta:
|
||||
|
@ -2,10 +2,11 @@ from __future__ import unicode_literals
|
||||
|
||||
from rest_framework import serializers
|
||||
from rest_framework.validators import UniqueTogetherValidator
|
||||
from taggit.models import Tag
|
||||
|
||||
from dcim.api.serializers import NestedDeviceSerializer
|
||||
from secrets.models import Secret, SecretRole
|
||||
from utilities.api import ValidatedModelSerializer, WritableNestedSerializer
|
||||
from utilities.api import TagField, ValidatedModelSerializer, WritableNestedSerializer
|
||||
|
||||
|
||||
#
|
||||
@ -35,10 +36,11 @@ class SecretSerializer(ValidatedModelSerializer):
|
||||
device = NestedDeviceSerializer()
|
||||
role = NestedSecretRoleSerializer()
|
||||
plaintext = serializers.CharField()
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Secret
|
||||
fields = ['id', 'device', 'role', 'name', 'plaintext', 'hash', 'created', 'last_updated']
|
||||
fields = ['id', 'device', 'role', 'name', 'plaintext', 'hash', 'tags', 'created', 'last_updated']
|
||||
validators = []
|
||||
|
||||
def validate(self, data):
|
||||
|
@ -4,6 +4,7 @@ from Crypto.Cipher import PKCS1_OAEP
|
||||
from Crypto.PublicKey import RSA
|
||||
from django import forms
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.models import Device
|
||||
from utilities.forms import BootstrapMixin, BulkEditForm, FilterChoiceField, FlexibleModelChoiceField, SlugField
|
||||
@ -70,10 +71,11 @@ class SecretForm(BootstrapMixin, forms.ModelForm):
|
||||
label='Plaintext (verify)',
|
||||
widget=forms.PasswordInput()
|
||||
)
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Secret
|
||||
fields = ['role', 'name', 'plaintext', 'plaintext2']
|
||||
fields = ['role', 'name', 'plaintext', 'plaintext2', 'tags']
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
|
@ -12,6 +12,7 @@ from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import force_bytes, python_2_unicode_compatible
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from utilities.models import CreatedUpdatedModel
|
||||
from .exceptions import InvalidKey
|
||||
@ -336,6 +337,8 @@ class Secret(CreatedUpdatedModel):
|
||||
editable=False
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
plaintext = None
|
||||
csv_headers = ['device', 'role', 'name', 'plaintext']
|
||||
|
||||
|
@ -110,6 +110,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ circuit.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% with circuit.get_custom_fields as custom_fields %}
|
||||
|
@ -44,6 +44,12 @@
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block javascript %}
|
||||
|
@ -102,6 +102,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ provider.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Circuits</td>
|
||||
<td>
|
||||
|
@ -33,4 +33,10 @@
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -84,4 +84,10 @@
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -12,7 +12,6 @@
|
||||
{% render_field form.u_height %}
|
||||
{% render_field form.is_full_depth %}
|
||||
{% render_field form.interface_ordering %}
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
@ -38,4 +37,10 @@
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -11,7 +11,6 @@
|
||||
{% render_field form.group %}
|
||||
{% render_field form.role %}
|
||||
{% render_field form.serial %}
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
@ -44,4 +43,10 @@
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -13,7 +13,6 @@
|
||||
{% render_field form.asn %}
|
||||
{% render_field form.time_zone %}
|
||||
{% render_field form.description %}
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
@ -47,4 +46,10 @@
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -81,6 +81,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ aggregate.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -19,4 +19,10 @@
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -133,6 +133,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ ipaddress.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% with ipaddress.get_custom_fields as custom_fields %}
|
||||
|
@ -66,6 +66,12 @@
|
||||
{% render_field form.nat_inside %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% if form.custom_fields %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Custom Fields</strong></div>
|
||||
|
@ -121,6 +121,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ prefix.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Utilization</td>
|
||||
<td>{% utilization_graph prefix.get_utilization %}</td>
|
||||
|
@ -28,6 +28,12 @@
|
||||
{% render_field form.tenant %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% if form.custom_fields %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Custom Fields</strong></div>
|
||||
|
@ -80,6 +80,10 @@
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ vlan.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -21,6 +21,12 @@
|
||||
{% render_field form.tenant %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% if form.custom_fields %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Custom Fields</strong></div>
|
||||
|
@ -77,6 +77,10 @@
|
||||
<span class="text-muted">N/A</span>
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ vrf.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -18,6 +18,12 @@
|
||||
{% render_field form.tenant %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% if form.custom_fields %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Custom Fields</strong></div>
|
||||
|
@ -55,6 +55,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ secret.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -54,6 +54,12 @@
|
||||
{% render_field form.plaintext2 %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
@ -68,6 +68,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ tenant.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% with tenant.get_custom_fields as custom_fields %}
|
||||
|
@ -26,4 +26,10 @@
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -76,6 +76,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ cluster.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Virtual Machines</td>
|
||||
<td><a href="{% url 'virtualization:virtualmachine_list' %}?cluster_id={{ cluster.pk }}">{{ cluster.virtual_machines.count }}</a></td>
|
||||
|
34
netbox/templates/virtualization/cluster_edit.html
Normal file
34
netbox/templates/virtualization/cluster_edit.html
Normal file
@ -0,0 +1,34 @@
|
||||
{% extends 'utilities/obj_edit.html' %}
|
||||
{% load form_helpers %}
|
||||
|
||||
{% block form %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Cluster</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.name %}
|
||||
{% render_field form.type %}
|
||||
{% render_field form.group %}
|
||||
{% render_field form.site %}
|
||||
</div>
|
||||
</div>
|
||||
{% if form.custom_fields %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Custom Fields</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_custom_fields form %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Comments</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
@ -121,6 +121,10 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tags</td>
|
||||
<td>{{ vm.tags.all|join:" " }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% include 'inc/custom_fields_panel.html' with custom_fields=vm.get_custom_fields %}
|
||||
|
@ -54,4 +54,10 @@
|
||||
{% render_field form.comments %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading"><strong>Tags</strong></div>
|
||||
<div class="panel-body">
|
||||
{% render_field form.tags %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
@ -1,10 +1,11 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework import serializers
|
||||
from taggit.models import Tag
|
||||
|
||||
from extras.api.customfields import CustomFieldModelSerializer
|
||||
from tenancy.models import Tenant, TenantGroup
|
||||
from utilities.api import ValidatedModelSerializer, WritableNestedSerializer
|
||||
from utilities.api import TagField, ValidatedModelSerializer, WritableNestedSerializer
|
||||
|
||||
|
||||
#
|
||||
@ -32,10 +33,14 @@ class NestedTenantGroupSerializer(WritableNestedSerializer):
|
||||
|
||||
class TenantSerializer(CustomFieldModelSerializer):
|
||||
group = NestedTenantGroupSerializer(required=False)
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Tenant
|
||||
fields = ['id', 'name', 'slug', 'group', 'description', 'comments', 'custom_fields', 'created', 'last_updated']
|
||||
fields = [
|
||||
'id', 'name', 'slug', 'group', 'description', 'comments', 'tags', 'custom_fields', 'created',
|
||||
'last_updated',
|
||||
]
|
||||
|
||||
|
||||
class NestedTenantSerializer(WritableNestedSerializer):
|
||||
|
@ -2,6 +2,7 @@ from __future__ import unicode_literals
|
||||
|
||||
from django import forms
|
||||
from django.db.models import Count
|
||||
from taggit.forms import TagField
|
||||
|
||||
from extras.forms import CustomFieldForm, CustomFieldBulkEditForm, CustomFieldFilterForm
|
||||
from utilities.forms import (
|
||||
@ -40,10 +41,11 @@ class TenantGroupCSVForm(forms.ModelForm):
|
||||
class TenantForm(BootstrapMixin, CustomFieldForm):
|
||||
slug = SlugField()
|
||||
comments = CommentField()
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Tenant
|
||||
fields = ['name', 'slug', 'group', 'description', 'comments']
|
||||
fields = ['name', 'slug', 'group', 'description', 'comments', 'tags']
|
||||
|
||||
|
||||
class TenantCSVForm(forms.ModelForm):
|
||||
|
@ -4,6 +4,7 @@ from django.contrib.contenttypes.fields import GenericRelation
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from extras.models import CustomFieldModel
|
||||
from utilities.models import CreatedUpdatedModel
|
||||
@ -74,6 +75,8 @@ class Tenant(CreatedUpdatedModel, CustomFieldModel):
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = ['name', 'slug', 'group', 'description', 'comments']
|
||||
|
||||
class Meta:
|
||||
|
@ -1,14 +1,15 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from rest_framework import serializers
|
||||
from taggit.models import Tag
|
||||
|
||||
from dcim.api.serializers import NestedDeviceRoleSerializer, NestedPlatformSerializer, NestedSiteSerializer
|
||||
from dcim.constants import IFACE_FF_VIRTUAL, IFACE_MODE_CHOICES
|
||||
from dcim.constants import IFACE_MODE_CHOICES
|
||||
from dcim.models import Interface
|
||||
from extras.api.customfields import CustomFieldModelSerializer
|
||||
from ipam.models import IPAddress, VLAN
|
||||
from tenancy.api.serializers import NestedTenantSerializer
|
||||
from utilities.api import ChoiceFieldSerializer, ValidatedModelSerializer, WritableNestedSerializer
|
||||
from utilities.api import ChoiceFieldSerializer, TagField, ValidatedModelSerializer, WritableNestedSerializer
|
||||
from virtualization.constants import VM_STATUS_CHOICES
|
||||
from virtualization.models import Cluster, ClusterGroup, ClusterType, VirtualMachine
|
||||
|
||||
@ -59,10 +60,13 @@ class ClusterSerializer(CustomFieldModelSerializer):
|
||||
type = NestedClusterTypeSerializer()
|
||||
group = NestedClusterGroupSerializer(required=False, allow_null=True)
|
||||
site = NestedSiteSerializer(required=False, allow_null=True)
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = Cluster
|
||||
fields = ['id', 'name', 'type', 'group', 'site', 'comments', 'custom_fields', 'created', 'last_updated']
|
||||
fields = [
|
||||
'id', 'name', 'type', 'group', 'site', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
|
||||
|
||||
class NestedClusterSerializer(WritableNestedSerializer):
|
||||
@ -95,12 +99,13 @@ class VirtualMachineSerializer(CustomFieldModelSerializer):
|
||||
primary_ip = VirtualMachineIPAddressSerializer(read_only=True)
|
||||
primary_ip4 = VirtualMachineIPAddressSerializer(required=False, allow_null=True)
|
||||
primary_ip6 = VirtualMachineIPAddressSerializer(required=False, allow_null=True)
|
||||
tags = TagField(queryset=Tag.objects.all(), required=False, many=True)
|
||||
|
||||
class Meta:
|
||||
model = VirtualMachine
|
||||
fields = [
|
||||
'id', 'name', 'status', 'cluster', 'role', 'tenant', 'platform', 'primary_ip', 'primary_ip4', 'primary_ip6',
|
||||
'vcpus', 'memory', 'disk', 'comments', 'custom_fields', 'created', 'last_updated',
|
||||
'vcpus', 'memory', 'disk', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
|
||||
]
|
||||
|
||||
|
||||
|
@ -4,6 +4,7 @@ from django import forms
|
||||
from django.core.exceptions import ValidationError
|
||||
from django.db.models import Count
|
||||
from mptt.forms import TreeNodeChoiceField
|
||||
from taggit.forms import TagField
|
||||
|
||||
from dcim.constants import IFACE_FF_VIRTUAL, IFACE_MODE_ACCESS, IFACE_MODE_TAGGED_ALL
|
||||
from dcim.forms import INTERFACE_MODE_HELP_TEXT
|
||||
@ -78,10 +79,11 @@ class ClusterGroupCSVForm(forms.ModelForm):
|
||||
|
||||
class ClusterForm(BootstrapMixin, CustomFieldForm):
|
||||
comments = CommentField(widget=SmallTextarea)
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = Cluster
|
||||
fields = ['name', 'type', 'group', 'site', 'comments']
|
||||
fields = ['name', 'type', 'group', 'site', 'comments', 'tags']
|
||||
|
||||
|
||||
class ClusterCSVForm(forms.ModelForm):
|
||||
@ -244,12 +246,13 @@ class VirtualMachineForm(BootstrapMixin, TenancyForm, CustomFieldForm):
|
||||
api_url='/api/virtualization/clusters/?group_id={{cluster_group}}'
|
||||
)
|
||||
)
|
||||
tags = TagField(required=False)
|
||||
|
||||
class Meta:
|
||||
model = VirtualMachine
|
||||
fields = [
|
||||
'name', 'status', 'cluster_group', 'cluster', 'role', 'tenant', 'platform', 'primary_ip4', 'primary_ip6',
|
||||
'vcpus', 'memory', 'disk', 'comments',
|
||||
'vcpus', 'memory', 'disk', 'comments', 'tags',
|
||||
]
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -6,6 +6,7 @@ from django.core.exceptions import ValidationError
|
||||
from django.db import models
|
||||
from django.urls import reverse
|
||||
from django.utils.encoding import python_2_unicode_compatible
|
||||
from taggit.managers import TaggableManager
|
||||
|
||||
from dcim.models import Device
|
||||
from extras.models import CustomFieldModel
|
||||
@ -124,6 +125,8 @@ class Cluster(CreatedUpdatedModel, CustomFieldModel):
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = ['name', 'type', 'group', 'site', 'comments']
|
||||
|
||||
class Meta:
|
||||
@ -242,6 +245,8 @@ class VirtualMachine(CreatedUpdatedModel, CustomFieldModel):
|
||||
object_id_field='obj_id'
|
||||
)
|
||||
|
||||
tags = TaggableManager()
|
||||
|
||||
csv_headers = [
|
||||
'name', 'status', 'role', 'cluster', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments',
|
||||
]
|
||||
|
@ -126,6 +126,7 @@ class ClusterView(View):
|
||||
|
||||
class ClusterCreateView(PermissionRequiredMixin, ObjectEditView):
|
||||
permission_required = 'virtualization.add_cluster'
|
||||
template_name = 'virtualization/cluster_edit.html'
|
||||
model = Cluster
|
||||
model_form = forms.ClusterForm
|
||||
|
||||
|
Reference in New Issue
Block a user