Merge branch 'feature' into 5284-vlangroup-scope

This commit is contained in:
Jeremy Stretch 2021-03-10 14:51:11 -05:00
commit f4e49495e2
24 changed files with 62 additions and 96 deletions

View File

@ -1,12 +1,11 @@
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.fields import ASNField from dcim.fields import ASNField
from dcim.models import CableTermination, PathEndpoint from dcim.models import CableTermination, PathEndpoint
from extras.models import ObjectChange, TaggedItem from extras.models import ObjectChange
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import BigIDModel, ChangeLoggingMixin, OrganizationalModel, PrimaryModel from netbox.models import BigIDModel, ChangeLoggedModel, OrganizationalModel, PrimaryModel
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
from .choices import * from .choices import *
from .querysets import CircuitQuerySet from .querysets import CircuitQuerySet
@ -60,7 +59,6 @@ class Provider(PrimaryModel):
comments = models.TextField( comments = models.TextField(
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()
@ -184,7 +182,6 @@ class Circuit(PrimaryModel):
) )
objects = CircuitQuerySet.as_manager() objects = CircuitQuerySet.as_manager()
tags = TaggableManager(through=TaggedItem)
csv_headers = [ csv_headers = [
'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments', 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
@ -234,7 +231,8 @@ class Circuit(PrimaryModel):
return self._get_termination('Z') return self._get_termination('Z')
class CircuitTermination(ChangeLoggingMixin, BigIDModel, PathEndpoint, CableTermination): @extras_features('webhooks')
class CircuitTermination(ChangeLoggedModel, PathEndpoint, CableTermination):
circuit = models.ForeignKey( circuit = models.ForeignKey(
to='circuits.Circuit', to='circuits.Circuit',
on_delete=models.CASCADE, on_delete=models.CASCADE,

View File

@ -6,13 +6,11 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models from django.db import models
from django.db.models import Sum from django.db.models import Sum
from django.urls import reverse from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.fields import PathField from dcim.fields import PathField
from dcim.utils import decompile_path_node, object_to_path_node, path_node_to_object from dcim.utils import decompile_path_node, object_to_path_node, path_node_to_object
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import BigIDModel, PrimaryModel from netbox.models import BigIDModel, PrimaryModel
from utilities.fields import ColorField from utilities.fields import ColorField
@ -108,7 +106,6 @@ class Cable(PrimaryModel):
blank=True, blank=True,
null=True null=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -5,7 +5,7 @@ from django.db import models
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import BigIDModel, ChangeLoggingMixin from netbox.models import ChangeLoggedModel
from utilities.fields import NaturalOrderingField from utilities.fields import NaturalOrderingField
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
from utilities.ordering import naturalize_interface from utilities.ordering import naturalize_interface
@ -26,7 +26,7 @@ __all__ = (
) )
class ComponentTemplateModel(ChangeLoggingMixin, BigIDModel): class ComponentTemplateModel(ChangeLoggedModel):
device_type = models.ForeignKey( device_type = models.ForeignKey(
to='dcim.DeviceType', to='dcim.DeviceType',
on_delete=models.CASCADE, on_delete=models.CASCADE,
@ -76,7 +76,7 @@ class ComponentTemplateModel(ChangeLoggingMixin, BigIDModel):
return super().to_objectchange(action, related_object=device_type) return super().to_objectchange(action, related_object=device_type)
@extras_features('custom_fields', 'export_templates', 'webhooks') @extras_features('webhooks')
class ConsolePortTemplate(ComponentTemplateModel): class ConsolePortTemplate(ComponentTemplateModel):
""" """
A template for a ConsolePort to be created for a new Device. A template for a ConsolePort to be created for a new Device.
@ -100,7 +100,7 @@ class ConsolePortTemplate(ComponentTemplateModel):
) )
@extras_features('custom_fields', 'export_templates', 'webhooks') @extras_features('webhooks')
class ConsoleServerPortTemplate(ComponentTemplateModel): class ConsoleServerPortTemplate(ComponentTemplateModel):
""" """
A template for a ConsoleServerPort to be created for a new Device. A template for a ConsoleServerPort to be created for a new Device.
@ -124,7 +124,7 @@ class ConsoleServerPortTemplate(ComponentTemplateModel):
) )
@extras_features('custom_fields', 'export_templates', 'webhooks') @extras_features('webhooks')
class PowerPortTemplate(ComponentTemplateModel): class PowerPortTemplate(ComponentTemplateModel):
""" """
A template for a PowerPort to be created for a new Device. A template for a PowerPort to be created for a new Device.
@ -171,7 +171,7 @@ class PowerPortTemplate(ComponentTemplateModel):
}) })
@extras_features('custom_fields', 'export_templates', 'webhooks') @extras_features('webhooks')
class PowerOutletTemplate(ComponentTemplateModel): class PowerOutletTemplate(ComponentTemplateModel):
""" """
A template for a PowerOutlet to be created for a new Device. A template for a PowerOutlet to be created for a new Device.
@ -223,7 +223,7 @@ class PowerOutletTemplate(ComponentTemplateModel):
) )
@extras_features('custom_fields', 'export_templates', 'webhooks') @extras_features('webhooks')
class InterfaceTemplate(ComponentTemplateModel): class InterfaceTemplate(ComponentTemplateModel):
""" """
A template for a physical data interface on a new Device. A template for a physical data interface on a new Device.
@ -258,7 +258,7 @@ class InterfaceTemplate(ComponentTemplateModel):
) )
@extras_features('custom_fields', 'export_templates', 'webhooks') @extras_features('webhooks')
class FrontPortTemplate(ComponentTemplateModel): class FrontPortTemplate(ComponentTemplateModel):
""" """
Template for a pass-through port on the front of a new Device. Template for a pass-through port on the front of a new Device.
@ -319,7 +319,7 @@ class FrontPortTemplate(ComponentTemplateModel):
) )
@extras_features('custom_fields', 'export_templates', 'webhooks') @extras_features('webhooks')
class RearPortTemplate(ComponentTemplateModel): class RearPortTemplate(ComponentTemplateModel):
""" """
Template for a pass-through port on the rear of a new Device. Template for a pass-through port on the rear of a new Device.
@ -350,7 +350,7 @@ class RearPortTemplate(ComponentTemplateModel):
) )
@extras_features('custom_fields', 'export_templates', 'webhooks') @extras_features('webhooks')
class DeviceBayTemplate(ComponentTemplateModel): class DeviceBayTemplate(ComponentTemplateModel):
""" """
A template for a DeviceBay to be created for a new parent Device. A template for a DeviceBay to be created for a new parent Device.

View File

@ -6,12 +6,10 @@ from django.db import models
from django.db.models import Sum from django.db.models import Sum
from django.urls import reverse from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.fields import MACAddressField from dcim.fields import MACAddressField
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import PrimaryModel from netbox.models import PrimaryModel
from utilities.fields import NaturalOrderingField from utilities.fields import NaturalOrderingField
@ -227,7 +225,6 @@ class ConsolePort(ComponentModel, CableTermination, PathEndpoint):
null=True, null=True,
help_text='Port speed in bits per second' help_text='Port speed in bits per second'
) )
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description'] csv_headers = ['device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description']
@ -271,7 +268,6 @@ class ConsoleServerPort(ComponentModel, CableTermination, PathEndpoint):
null=True, null=True,
help_text='Port speed in bits per second' help_text='Port speed in bits per second'
) )
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description'] csv_headers = ['device', 'name', 'label', 'type', 'speed', 'mark_connected', 'description']
@ -321,7 +317,6 @@ class PowerPort(ComponentModel, CableTermination, PathEndpoint):
validators=[MinValueValidator(1)], validators=[MinValueValidator(1)],
help_text="Allocated power draw (watts)" help_text="Allocated power draw (watts)"
) )
tags = TaggableManager(through=TaggedItem)
csv_headers = [ csv_headers = [
'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description', 'device', 'name', 'label', 'type', 'mark_connected', 'maximum_draw', 'allocated_draw', 'description',
@ -434,7 +429,6 @@ class PowerOutlet(ComponentModel, CableTermination, PathEndpoint):
blank=True, blank=True,
help_text="Phase (for three-phase feeds)" help_text="Phase (for three-phase feeds)"
) )
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'power_port', 'feed_leg', 'description'] csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'power_port', 'feed_leg', 'description']
@ -568,7 +562,6 @@ class Interface(ComponentModel, BaseInterface, CableTermination, PathEndpoint):
object_id_field='assigned_object_id', object_id_field='assigned_object_id',
related_query_name='interface' related_query_name='interface'
) )
tags = TaggableManager(through=TaggedItem)
csv_headers = [ csv_headers = [
'device', 'name', 'label', 'parent', 'lag', 'type', 'enabled', 'mark_connected', 'mac_address', 'mtu', 'device', 'name', 'label', 'parent', 'lag', 'type', 'enabled', 'mark_connected', 'mac_address', 'mtu',
@ -705,7 +698,6 @@ class FrontPort(ComponentModel, CableTermination):
MaxValueValidator(REARPORT_POSITIONS_MAX) MaxValueValidator(REARPORT_POSITIONS_MAX)
] ]
) )
tags = TaggableManager(through=TaggedItem)
csv_headers = [ csv_headers = [
'device', 'name', 'label', 'type', 'mark_connected', 'rear_port', 'rear_port_position', 'description', 'device', 'name', 'label', 'type', 'mark_connected', 'rear_port', 'rear_port_position', 'description',
@ -766,7 +758,6 @@ class RearPort(ComponentModel, CableTermination):
MaxValueValidator(REARPORT_POSITIONS_MAX) MaxValueValidator(REARPORT_POSITIONS_MAX)
] ]
) )
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'positions', 'description'] csv_headers = ['device', 'name', 'label', 'type', 'mark_connected', 'positions', 'description']
@ -816,7 +807,6 @@ class DeviceBay(ComponentModel):
blank=True, blank=True,
null=True null=True
) )
tags = TaggableManager(through=TaggedItem)
csv_headers = ['device', 'name', 'label', 'installed_device', 'description'] csv_headers = ['device', 'name', 'label', 'installed_device', 'description']
@ -909,8 +899,6 @@ class InventoryItem(MPTTModel, ComponentModel):
help_text='This item was automatically discovered' help_text='This item was automatically discovered'
) )
tags = TaggableManager(through=TaggedItem)
objects = TreeManager() objects = TreeManager()
csv_headers = [ csv_headers = [

View File

@ -9,11 +9,10 @@ from django.db import models
from django.db.models import F, ProtectedError from django.db.models import F, ProtectedError
from django.urls import reverse from django.urls import reverse
from django.utils.safestring import mark_safe from django.utils.safestring import mark_safe
from taggit.managers import TaggableManager
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from extras.models import ConfigContextModel, TaggedItem from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet from extras.querysets import ConfigContextModelQuerySet
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import OrganizationalModel, PrimaryModel from netbox.models import OrganizationalModel, PrimaryModel
@ -136,7 +135,6 @@ class DeviceType(PrimaryModel):
comments = models.TextField( comments = models.TextField(
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()
@ -601,7 +599,6 @@ class Device(PrimaryModel, ConfigContextModel):
object_id_field='assigned_object_id', object_id_field='assigned_object_id',
related_query_name='device' related_query_name='device'
) )
tags = TaggableManager(through=TaggedItem)
objects = ConfigContextModelQuerySet.as_manager() objects = ConfigContextModelQuerySet.as_manager()
@ -916,7 +913,6 @@ class VirtualChassis(PrimaryModel):
max_length=30, max_length=30,
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -2,11 +2,9 @@ from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import PrimaryModel from netbox.models import PrimaryModel
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
@ -41,7 +39,6 @@ class PowerPanel(PrimaryModel):
name = models.CharField( name = models.CharField(
max_length=100 max_length=100
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()
@ -133,7 +130,6 @@ class PowerFeed(PrimaryModel, PathEndpoint, CableTermination):
comments = models.TextField( comments = models.TextField(
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -11,12 +11,10 @@ from django.db import models
from django.db.models import Count, Sum from django.db.models import Count, Sum
from django.urls import reverse from django.urls import reverse
from mptt.models import TreeForeignKey from mptt.models import TreeForeignKey
from taggit.managers import TaggableManager
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.elevations import RackElevationSVG from dcim.elevations import RackElevationSVG
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import NestedGroupModel, OrganizationalModel, PrimaryModel from netbox.models import NestedGroupModel, OrganizationalModel, PrimaryModel
from utilities.choices import ColorChoices from utilities.choices import ColorChoices
@ -251,7 +249,6 @@ class Rack(PrimaryModel):
images = GenericRelation( images = GenericRelation(
to='extras.ImageAttachment' to='extras.ImageAttachment'
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()
@ -558,7 +555,6 @@ class RackReservation(PrimaryModel):
description = models.CharField( description = models.CharField(
max_length=200 max_length=200
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -2,13 +2,11 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from mptt.models import TreeForeignKey from mptt.models import TreeForeignKey
from taggit.managers import TaggableManager
from timezone_field import TimeZoneField from timezone_field import TimeZoneField
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.fields import ASNField from dcim.fields import ASNField
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import NestedGroupModel, PrimaryModel from netbox.models import NestedGroupModel, PrimaryModel
from utilities.fields import NaturalOrderingField from utilities.fields import NaturalOrderingField
@ -232,7 +230,6 @@ class Site(PrimaryModel):
images = GenericRelation( images = GenericRelation(
to='extras.ImageAttachment' to='extras.ImageAttachment'
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -16,7 +16,7 @@ from extras.choices import *
from extras.constants import * from extras.constants import *
from extras.querysets import ConfigContextQuerySet from extras.querysets import ConfigContextQuerySet
from extras.utils import extras_features, FeatureQuery, image_upload from extras.utils import extras_features, FeatureQuery, image_upload
from netbox.models import BigIDModel, ChangeLoggingMixin from netbox.models import BigIDModel, ChangeLoggedModel
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
from utilities.utils import deepmerge, render_jinja2 from utilities.utils import deepmerge, render_jinja2
@ -379,7 +379,8 @@ class ImageAttachment(BigIDModel):
# Config contexts # Config contexts
# #
class ConfigContext(ChangeLoggingMixin, BigIDModel): @extras_features('webhooks')
class ConfigContext(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

View File

@ -2,7 +2,8 @@ from django.db import models
from django.utils.text import slugify from django.utils.text import slugify
from taggit.models import TagBase, GenericTaggedItemBase from taggit.models import TagBase, GenericTaggedItemBase
from netbox.models import BigIDModel, ChangeLoggingMixin from extras.utils import extras_features
from netbox.models import BigIDModel, ChangeLoggedModel
from utilities.choices import ColorChoices from utilities.choices import ColorChoices
from utilities.fields import ColorField from utilities.fields import ColorField
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
@ -12,7 +13,8 @@ from utilities.querysets import RestrictedQuerySet
# Tags # Tags
# #
class Tag(ChangeLoggingMixin, BigIDModel, TagBase): @extras_features('webhooks')
class Tag(ChangeLoggedModel, TagBase):
color = ColorField( color = ColorField(
default=ColorChoices.COLOR_GREY default=ColorChoices.COLOR_GREY
) )

View File

@ -6,10 +6,8 @@ from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.db.models import F from django.db.models import F
from django.urls import reverse from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.models import Device from dcim.models import Device
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import OrganizationalModel, PrimaryModel from netbox.models import OrganizationalModel, PrimaryModel
from ipam.choices import * from ipam.choices import *
@ -107,7 +105,6 @@ class Aggregate(PrimaryModel):
max_length=200, max_length=200,
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()
@ -292,7 +289,6 @@ class Prefix(PrimaryModel):
max_length=200, max_length=200,
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = PrefixQuerySet.as_manager() objects = PrefixQuerySet.as_manager()
@ -564,7 +560,6 @@ class IPAddress(PrimaryModel):
max_length=200, max_length=200,
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = IPAddressManager() objects = IPAddressManager()

View File

@ -3,9 +3,7 @@ from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from taggit.managers import TaggableManager
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from ipam.choices import * from ipam.choices import *
from ipam.constants import * from ipam.constants import *
@ -66,7 +64,6 @@ class Service(PrimaryModel):
max_length=200, max_length=200,
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -4,10 +4,8 @@ from django.core.exceptions import ValidationError
from django.core.validators import MaxValueValidator, MinValueValidator from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.models import Interface from dcim.models import Interface
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from ipam.choices import * from ipam.choices import *
from ipam.constants import * from ipam.constants import *
@ -149,7 +147,6 @@ class VLAN(PrimaryModel):
max_length=200, max_length=200,
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -1,8 +1,6 @@
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from taggit.managers import TaggableManager
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from ipam.constants import * from ipam.constants import *
from netbox.models import PrimaryModel from netbox.models import PrimaryModel
@ -59,7 +57,6 @@ class VRF(PrimaryModel):
related_name='exporting_vrfs', related_name='exporting_vrfs',
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()
@ -116,7 +113,6 @@ class RouteTarget(PrimaryModel):
blank=True, blank=True,
null=True null=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -5,6 +5,7 @@ from django.core.serializers.json import DjangoJSONEncoder
from django.core.validators import ValidationError from django.core.validators import ValidationError
from django.db import models from django.db import models
from mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager
from extras.choices import ObjectChangeActionChoices from extras.choices import ObjectChangeActionChoices
from utilities.mptt import TreeManager from utilities.mptt import TreeManager
@ -12,8 +13,7 @@ from utilities.utils import serialize_object
__all__ = ( __all__ = (
'BigIDModel', 'BigIDModel',
'ChangeLoggingMixin', 'ChangeLoggedModel',
'CustomFieldsMixin',
'NestedGroupModel', 'NestedGroupModel',
'OrganizationalModel', 'OrganizationalModel',
'PrimaryModel', 'PrimaryModel',
@ -137,12 +137,19 @@ class BigIDModel(models.Model):
abstract = True abstract = True
class ChangeLoggedModel(ChangeLoggingMixin, BigIDModel):
"""
Base model for all objects which support change logging.
"""
class Meta:
abstract = True
class PrimaryModel(ChangeLoggingMixin, CustomFieldsMixin, BigIDModel): class PrimaryModel(ChangeLoggingMixin, CustomFieldsMixin, BigIDModel):
""" """
Primary models represent real objects within the infrastructure being modeled. Primary models represent real objects within the infrastructure being modeled.
""" """
# TODO tags = TaggableManager(through='extras.TaggedItem')
# tags = TaggableManager(through=TaggedItem)
class Meta: class Meta:
abstract = True abstract = True

View File

@ -12,9 +12,7 @@ from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from django.utils.encoding import force_bytes from django.utils.encoding import force_bytes
from taggit.managers import TaggableManager
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import BigIDModel, OrganizationalModel, PrimaryModel from netbox.models import BigIDModel, OrganizationalModel, PrimaryModel
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
@ -312,7 +310,6 @@ class Secret(PrimaryModel):
max_length=128, max_length=128,
editable=False editable=False
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -57,9 +57,10 @@
</tr> </tr>
</table> </table>
</div> </div>
{% plugin_left_page object %} {% plugin_left_page object %}
</div> </div>
<div class="col-md-6"> <div class="col-md-6">
{% include 'inc/custom_fields_panel.html' %}
{% include 'extras/inc/tags_panel.html' with tags=object.tags.all %} {% include 'extras/inc/tags_panel.html' with tags=object.tags.all %}
{% plugin_right_page object %} {% plugin_right_page object %}
</div> </div>

View File

@ -31,6 +31,14 @@
{% render_field form.tagged_vlans %} {% render_field form.tagged_vlans %}
</div> </div>
</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 %}
{% endblock %} {% endblock %}
{% block buttons %} {% block buttons %}

View File

@ -1,12 +1,9 @@
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager
from extras.models import TaggedItem
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import NestedGroupModel, PrimaryModel from netbox.models import NestedGroupModel, PrimaryModel
from utilities.mptt import TreeManager
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
@ -42,8 +39,6 @@ class TenantGroup(NestedGroupModel):
blank=True blank=True
) )
objects = TreeManager()
csv_headers = ['name', 'slug', 'parent', 'description'] csv_headers = ['name', 'slug', 'parent', 'description']
class Meta: class Meta:
@ -89,7 +84,6 @@ class Tenant(PrimaryModel):
comments = models.TextField( comments = models.TextField(
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()

View File

@ -103,7 +103,7 @@ class VirtualMachineWithConfigContextSerializer(VirtualMachineSerializer):
# VM interfaces # VM interfaces
# #
class VMInterfaceSerializer(TaggedObjectSerializer, ValidatedModelSerializer): class VMInterfaceSerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail') url = serializers.HyperlinkedIdentityField(view_name='virtualization-api:vminterface-detail')
virtual_machine = NestedVirtualMachineSerializer() virtual_machine = NestedVirtualMachineSerializer()
mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False) mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
@ -119,7 +119,7 @@ class VMInterfaceSerializer(TaggedObjectSerializer, ValidatedModelSerializer):
model = VMInterface model = VMInterface
fields = [ fields = [
'id', 'url', 'virtual_machine', 'name', 'enabled', 'mtu', 'mac_address', 'description', 'mode', 'id', 'url', 'virtual_machine', 'name', 'enabled', 'mtu', 'mac_address', 'description', 'mode',
'untagged_vlan', 'tagged_vlans', 'tags', 'untagged_vlan', 'tagged_vlans', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
def validate(self, data): def validate(self, data):

View File

@ -237,7 +237,7 @@ class VirtualMachineFilterSet(
return queryset.exclude(params) return queryset.exclude(params)
class VMInterfaceFilterSet(BaseFilterSet): class VMInterfaceFilterSet(BaseFilterSet, CustomFieldModelFilterSet, CreatedUpdatedFilterSet):
q = django_filters.CharFilter( q = django_filters.CharFilter(
method='search', method='search',
label='Search', label='Search',

View File

@ -576,7 +576,7 @@ class VirtualMachineFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFil
# VM interfaces # VM interfaces
# #
class VMInterfaceForm(BootstrapMixin, InterfaceCommonForm, forms.ModelForm): class VMInterfaceForm(BootstrapMixin, InterfaceCommonForm, CustomFieldModelForm):
untagged_vlan = DynamicModelChoiceField( untagged_vlan = DynamicModelChoiceField(
queryset=VLAN.objects.all(), queryset=VLAN.objects.all(),
required=False, required=False,

View File

@ -1,4 +1,5 @@
import django.core.serializers.json import django.core.serializers.json
import taggit.managers
from django.db import migrations, models from django.db import migrations, models
@ -54,4 +55,14 @@ class Migration(migrations.Migration):
name='last_updated', name='last_updated',
field=models.DateTimeField(auto_now=True, null=True), field=models.DateTimeField(auto_now=True, null=True),
), ),
migrations.AddField(
model_name='vminterface',
name='custom_field_data',
field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
),
migrations.AlterField(
model_name='vminterface',
name='tags',
field=taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag'),
),
] ]

View File

@ -3,13 +3,12 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.models import BaseInterface, Device from dcim.models import BaseInterface, Device
from extras.models import ConfigContextModel, TaggedItem from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet from extras.querysets import ConfigContextModelQuerySet
from extras.utils import extras_features from extras.utils import extras_features
from netbox.models import BigIDModel, ChangeLoggingMixin, OrganizationalModel, PrimaryModel from netbox.models import OrganizationalModel, PrimaryModel
from utilities.fields import NaturalOrderingField from utilities.fields import NaturalOrderingField
from utilities.ordering import naturalize_interface from utilities.ordering import naturalize_interface
from utilities.query_functions import CollateAsChar from utilities.query_functions import CollateAsChar
@ -154,7 +153,6 @@ class Cluster(PrimaryModel):
comments = models.TextField( comments = models.TextField(
blank=True blank=True
) )
tags = TaggableManager(through=TaggedItem)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()
@ -281,7 +279,6 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
object_id_field='assigned_object_id', object_id_field='assigned_object_id',
related_query_name='virtual_machine' related_query_name='virtual_machine'
) )
tags = TaggableManager(through=TaggedItem)
objects = ConfigContextModelQuerySet.as_manager() objects = ConfigContextModelQuerySet.as_manager()
@ -372,9 +369,8 @@ class VirtualMachine(PrimaryModel, ConfigContextModel):
# Interfaces # Interfaces
# #
# TODO: Inherit from PrimaryModel @extras_features('custom_fields', 'custom_links', 'export_templates', 'webhooks')
@extras_features('export_templates', 'webhooks') class VMInterface(PrimaryModel, BaseInterface):
class VMInterface(ChangeLoggingMixin, BigIDModel, BaseInterface):
virtual_machine = models.ForeignKey( virtual_machine = models.ForeignKey(
to='virtualization.VirtualMachine', to='virtualization.VirtualMachine',
on_delete=models.CASCADE, on_delete=models.CASCADE,
@ -413,10 +409,6 @@ class VMInterface(ChangeLoggingMixin, BigIDModel, BaseInterface):
object_id_field='assigned_object_id', object_id_field='assigned_object_id',
related_query_name='vminterface' related_query_name='vminterface'
) )
tags = TaggableManager(
through=TaggedItem,
related_name='vminterface'
)
objects = RestrictedQuerySet.as_manager() objects = RestrictedQuerySet.as_manager()