Introduce has_feature() utility function

This commit is contained in:
Jeremy Stretch 2025-07-23 14:40:42 -04:00
parent e38ba29928
commit 0d8b6c78ae
6 changed files with 25 additions and 15 deletions

View File

@ -11,8 +11,8 @@ from mptt.models import MPTTModel
from core.choices import ObjectChangeActionChoices
from core.querysets import ObjectChangeQuerySet
from netbox.models.features import ChangeLoggingMixin
from netbox.models.features import has_feature
from utilities.data import shallow_compare_dict
from .contenttypes import ObjectType
__all__ = (
'ObjectChange',
@ -118,7 +118,7 @@ class ObjectChange(models.Model):
super().clean()
# Validate the assigned object type
if self.changed_object_type not in ObjectType.objects.with_feature('change_logging'):
if not has_feature(self.changed_object_type, 'change_logging'):
raise ValidationError(
_("Change logging is not supported for this object type ({type}).").format(
type=self.changed_object_type

View File

@ -20,6 +20,7 @@ from core.choices import JobStatusChoices
from core.dataclasses import JobLogEntry
from core.models import ObjectType
from core.signals import job_end, job_start
from netbox.models.features import has_feature
from utilities.json import JobLogDecoder
from utilities.querysets import RestrictedQuerySet
from utilities.rqworker import get_queue_for_model
@ -148,7 +149,7 @@ class Job(models.Model):
super().clean()
# Validate the assigned object type
if self.object_type and self.object_type not in ObjectType.objects.with_feature('jobs'):
if self.object_type and not has_feature(self.object_type, 'jobs'):
raise ValidationError(
_("Jobs cannot be assigned to this object type ({type}).").format(type=self.object_type)
)

View File

@ -12,17 +12,16 @@ from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from rest_framework.utils.encoders import JSONEncoder
from core.models import ObjectType
from extras.choices import *
from extras.conditions import ConditionSet, InvalidCondition
from extras.constants import *
from extras.utils import image_upload
from extras.models.mixins import RenderTemplateMixin
from extras.utils import image_upload
from netbox.config import get_config
from netbox.events import get_event_type_choices
from netbox.models import ChangeLoggedModel
from netbox.models.features import (
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin
CloningMixin, CustomFieldsMixin, CustomLinksMixin, ExportTemplatesMixin, SyncedDataMixin, TagsMixin, has_feature
)
from utilities.html import clean_html
from utilities.jinja2 import render_jinja2
@ -707,7 +706,7 @@ class ImageAttachment(ChangeLoggedModel):
super().clean()
# Validate the assigned object type
if self.object_type not in ObjectType.objects.with_feature('image_attachments'):
if not has_feature(self.object_type, 'image_attachments'):
raise ValidationError(
_("Image attachments cannot be assigned to this object type ({type}).").format(type=self.object_type)
)
@ -807,7 +806,7 @@ class JournalEntry(CustomFieldsMixin, CustomLinksMixin, TagsMixin, ExportTemplat
super().clean()
# Validate the assigned object type
if self.assigned_object_type not in ObjectType.objects.with_feature('journaling'):
if not has_feature(self.assigned_object_type, 'journaling'):
raise ValidationError(
_("Journaling is not supported for this object type ({type}).").format(type=self.assigned_object_type)
)
@ -863,7 +862,7 @@ class Bookmark(models.Model):
super().clean()
# Validate the assigned object type
if self.object_type not in ObjectType.objects.with_feature('bookmarks'):
if not has_feature(self.object_type, 'bookmarks'):
raise ValidationError(
_("Bookmarks cannot be assigned to this object type ({type}).").format(type=self.object_type)
)

View File

@ -7,9 +7,9 @@ from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from core.models import ObjectType
from extras.querysets import NotificationQuerySet
from netbox.models import ChangeLoggedModel
from netbox.models.features import has_feature
from netbox.registry import registry
from users.models import User
from utilities.querysets import RestrictedQuerySet
@ -94,7 +94,7 @@ class Notification(models.Model):
super().clean()
# Validate the assigned object type
if self.object_type not in ObjectType.objects.with_feature('notifications'):
if not has_feature(self.object_type, 'notifications'):
raise ValidationError(
_("Objects of this type ({type}) do not support notifications.").format(type=self.object_type)
)
@ -235,7 +235,7 @@ class Subscription(models.Model):
super().clean()
# Validate the assigned object type
if self.object_type not in ObjectType.objects.with_feature('notifications'):
if not has_feature(self.object_type, 'notifications'):
raise ValidationError(
_("Objects of this type ({type}) do not support notifications.").format(type=self.object_type)
)

View File

@ -3,6 +3,7 @@ from collections import defaultdict
from functools import cached_property
from django.contrib.contenttypes.fields import GenericRelation
from django.contrib.contenttypes.models import ContentType
from django.core.validators import ValidationError
from django.db import models
from django.db.models import Q
@ -39,6 +40,7 @@ __all__ = (
'NotificationsMixin',
'SyncedDataMixin',
'TagsMixin',
'has_feature',
'register_models',
)
@ -640,6 +642,15 @@ registry['model_features'].update({
})
def has_feature(model, feature):
"""
Returns True if the model supports the specified feature.
"""
if type(model) is ContentType:
model = model.model_class()
return feature in ObjectType.objects.get_for_model(model).features
def register_models(*models):
"""
Register one or more models in NetBox. This entails:

View File

@ -4,9 +4,8 @@ from django.db import models
from django.urls import reverse
from django.utils.translation import gettext_lazy as _
from core.models import ObjectType
from netbox.models import ChangeLoggedModel, NestedGroupModel, OrganizationalModel, PrimaryModel
from netbox.models.features import CustomFieldsMixin, ExportTemplatesMixin, TagsMixin
from netbox.models.features import CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, has_feature
from tenancy.choices import *
__all__ = (
@ -151,7 +150,7 @@ class ContactAssignment(CustomFieldsMixin, ExportTemplatesMixin, TagsMixin, Chan
super().clean()
# Validate the assigned object type
if self.object_type not in ObjectType.objects.with_feature('contacts'):
if not has_feature(self.object_type, 'contacts'):
raise ValidationError(
_("Contacts cannot be assigned to this object type ({type}).").format(type=self.object_type)
)