mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Merge pull request #10313 from netbox-community/10304-customfield-clone
Fixes #10304: Enable cloning for custom fields & custom links
This commit is contained in:
@ -14,7 +14,7 @@ from django.utils.safestring import mark_safe
|
|||||||
from extras.choices import *
|
from extras.choices import *
|
||||||
from extras.utils import FeatureQuery
|
from extras.utils import FeatureQuery
|
||||||
from netbox.models import ChangeLoggedModel
|
from netbox.models import ChangeLoggedModel
|
||||||
from netbox.models.features import ExportTemplatesMixin, WebhooksMixin
|
from netbox.models.features import CloningMixin, ExportTemplatesMixin, WebhooksMixin
|
||||||
from utilities import filters
|
from utilities import filters
|
||||||
from utilities.forms import (
|
from utilities.forms import (
|
||||||
CSVChoiceField, CSVMultipleChoiceField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
|
CSVChoiceField, CSVMultipleChoiceField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField,
|
||||||
@ -41,7 +41,7 @@ class CustomFieldManager(models.Manager.from_queryset(RestrictedQuerySet)):
|
|||||||
return self.get_queryset().filter(content_types=content_type)
|
return self.get_queryset().filter(content_types=content_type)
|
||||||
|
|
||||||
|
|
||||||
class CustomField(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
|
class CustomField(CloningMixin, ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
|
||||||
content_types = models.ManyToManyField(
|
content_types = models.ManyToManyField(
|
||||||
to=ContentType,
|
to=ContentType,
|
||||||
related_name='custom_fields',
|
related_name='custom_fields',
|
||||||
@ -143,8 +143,14 @@ class CustomField(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
|
|||||||
verbose_name='UI visibility',
|
verbose_name='UI visibility',
|
||||||
help_text='Specifies the visibility of custom field in the UI'
|
help_text='Specifies the visibility of custom field in the UI'
|
||||||
)
|
)
|
||||||
|
|
||||||
objects = CustomFieldManager()
|
objects = CustomFieldManager()
|
||||||
|
|
||||||
|
clone_fields = (
|
||||||
|
'content_types', 'type', 'object_type', 'group_name', 'description', 'required', 'filter_logic', 'default',
|
||||||
|
'weight', 'validation_minimum', 'validation_maximum', 'validation_regex', 'choices', 'ui_visibility',
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['group_name', 'weight', 'name']
|
ordering = ['group_name', 'weight', 'name']
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ from extras.conditions import ConditionSet
|
|||||||
from extras.utils import FeatureQuery, image_upload
|
from extras.utils import FeatureQuery, image_upload
|
||||||
from netbox.models import ChangeLoggedModel
|
from netbox.models import ChangeLoggedModel
|
||||||
from netbox.models.features import (
|
from netbox.models.features import (
|
||||||
CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, JobResultsMixin, TagsMixin, WebhooksMixin,
|
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, JobResultsMixin, TagsMixin, WebhooksMixin,
|
||||||
)
|
)
|
||||||
from utilities.querysets import RestrictedQuerySet
|
from utilities.querysets import RestrictedQuerySet
|
||||||
from utilities.utils import render_jinja2
|
from utilities.utils import render_jinja2
|
||||||
@ -187,7 +187,7 @@ class Webhook(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
|
|||||||
return render_jinja2(self.payload_url, context)
|
return render_jinja2(self.payload_url, context)
|
||||||
|
|
||||||
|
|
||||||
class CustomLink(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
|
class CustomLink(CloningMixin, ExportTemplatesMixin, WebhooksMixin, 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.
|
||||||
@ -230,6 +230,10 @@ class CustomLink(ExportTemplatesMixin, WebhooksMixin, ChangeLoggedModel):
|
|||||||
help_text="Force link to open in a new window"
|
help_text="Force link to open in a new window"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
clone_fields = (
|
||||||
|
'content_type', 'enabled', 'weight', 'group_name', 'button_class', 'new_window',
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
ordering = ['group_name', 'weight', 'name']
|
ordering = ['group_name', 'weight', 'name']
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@ 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 extras.utils import is_taggable
|
|
||||||
from utilities.mptt import TreeManager
|
from utilities.mptt import TreeManager
|
||||||
from utilities.querysets import RestrictedQuerySet
|
from utilities.querysets import RestrictedQuerySet
|
||||||
from netbox.models.features import *
|
from netbox.models.features import *
|
||||||
@ -32,7 +31,7 @@ class NetBoxFeatureSet(
|
|||||||
def get_prerequisite_models(cls):
|
def get_prerequisite_models(cls):
|
||||||
"""
|
"""
|
||||||
Return a list of model types that are required to create this model or empty list if none. This is used for
|
Return a list of model types that are required to create this model or empty list if none. This is used for
|
||||||
showing prequisite warnings in the UI on the list and detail views.
|
showing prerequisite warnings in the UI on the list and detail views.
|
||||||
"""
|
"""
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@ -52,7 +51,7 @@ class ChangeLoggedModel(ChangeLoggingMixin, CustomValidationMixin, models.Model)
|
|||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
|
|
||||||
class NetBoxModel(NetBoxFeatureSet, models.Model):
|
class NetBoxModel(CloningMixin, NetBoxFeatureSet, models.Model):
|
||||||
"""
|
"""
|
||||||
Primary models represent real objects within the infrastructure being modeled.
|
Primary models represent real objects within the infrastructure being modeled.
|
||||||
"""
|
"""
|
||||||
@ -61,25 +60,6 @@ class NetBoxModel(NetBoxFeatureSet, models.Model):
|
|||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def clone(self):
|
|
||||||
"""
|
|
||||||
Return a dictionary of attributes suitable for creating a copy of the current instance. This is used for pre-
|
|
||||||
populating an object creation form in the UI.
|
|
||||||
"""
|
|
||||||
attrs = {}
|
|
||||||
|
|
||||||
for field_name in getattr(self, 'clone_fields', []):
|
|
||||||
field = self._meta.get_field(field_name)
|
|
||||||
field_value = field.value_from_object(self)
|
|
||||||
if field_value not in (None, ''):
|
|
||||||
attrs[field_name] = field_value
|
|
||||||
|
|
||||||
# Include tags (if applicable)
|
|
||||||
if is_taggable(self):
|
|
||||||
attrs['tags'] = [tag.pk for tag in self.tags.all()]
|
|
||||||
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
|
|
||||||
class NestedGroupModel(NetBoxFeatureSet, MPTTModel):
|
class NestedGroupModel(NetBoxFeatureSet, MPTTModel):
|
||||||
"""
|
"""
|
||||||
|
@ -10,12 +10,13 @@ from django.db import models
|
|||||||
from taggit.managers import TaggableManager
|
from taggit.managers import TaggableManager
|
||||||
|
|
||||||
from extras.choices import CustomFieldVisibilityChoices, ObjectChangeActionChoices
|
from extras.choices import CustomFieldVisibilityChoices, ObjectChangeActionChoices
|
||||||
from extras.utils import register_features
|
from extras.utils import is_taggable, register_features
|
||||||
from netbox.signals import post_clean
|
from netbox.signals import post_clean
|
||||||
from utilities.utils import serialize_object
|
from utilities.utils import serialize_object
|
||||||
|
|
||||||
__all__ = (
|
__all__ = (
|
||||||
'ChangeLoggingMixin',
|
'ChangeLoggingMixin',
|
||||||
|
'CloningMixin',
|
||||||
'CustomFieldsMixin',
|
'CustomFieldsMixin',
|
||||||
'CustomLinksMixin',
|
'CustomLinksMixin',
|
||||||
'CustomValidationMixin',
|
'CustomValidationMixin',
|
||||||
@ -82,6 +83,33 @@ class ChangeLoggingMixin(models.Model):
|
|||||||
return objectchange
|
return objectchange
|
||||||
|
|
||||||
|
|
||||||
|
class CloningMixin(models.Model):
|
||||||
|
"""
|
||||||
|
Provides the clone() method used to prepare a copy of existing objects.
|
||||||
|
"""
|
||||||
|
class Meta:
|
||||||
|
abstract = True
|
||||||
|
|
||||||
|
def clone(self):
|
||||||
|
"""
|
||||||
|
Return a dictionary of attributes suitable for creating a copy of the current instance. This is used for pre-
|
||||||
|
populating an object creation form in the UI.
|
||||||
|
"""
|
||||||
|
attrs = {}
|
||||||
|
|
||||||
|
for field_name in getattr(self, 'clone_fields', []):
|
||||||
|
field = self._meta.get_field(field_name)
|
||||||
|
field_value = field.value_from_object(self)
|
||||||
|
if field_value not in (None, ''):
|
||||||
|
attrs[field_name] = field_value
|
||||||
|
|
||||||
|
# Include tags (if applicable)
|
||||||
|
if is_taggable(self):
|
||||||
|
attrs['tags'] = [tag.pk for tag in self.tags.all()]
|
||||||
|
|
||||||
|
return attrs
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldsMixin(models.Model):
|
class CustomFieldsMixin(models.Model):
|
||||||
"""
|
"""
|
||||||
Enables support for custom fields.
|
Enables support for custom fields.
|
||||||
|
Reference in New Issue
Block a user