Quellcode durchsuchen

Revert "refactor extras registry"

This reverts commit c189895f6c17bd64de21e419a2f6678342d62477.
John Anderson vor 6 Jahren
Ursprung
Commit
6ea15cec6f

+ 2 - 2
netbox/dcim/models/__init__.py

@@ -21,7 +21,7 @@ from dcim.constants import *
 from dcim.fields import ASNField
 from dcim.fields import ASNField
 from dcim.elevations import RackElevationSVG
 from dcim.elevations import RackElevationSVG
 from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange, TaggedItem
 from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange, TaggedItem
-from extras.utils import extras_features
+from extras.utils import extras_functionality
 from utilities.fields import ColorField, NaturalOrderingField
 from utilities.fields import ColorField, NaturalOrderingField
 from utilities.models import ChangeLoggedModel
 from utilities.models import ChangeLoggedModel
 from utilities.utils import serialize_object, to_meters
 from utilities.utils import serialize_object, to_meters
@@ -1221,7 +1221,7 @@ class Platform(ChangeLoggedModel):
         )
         )
 
 
 
 
-@extras_features(['webhooks', 'custom_fields', 'export_templates', 'custom_links', 'graphs'])
+@extras_functionality(['webhooks', 'custom_fields', 'export_templates', 'custom_links', 'graphs'])
 class Device(ChangeLoggedModel, ConfigContextModel, CustomFieldModel):
 class Device(ChangeLoggedModel, ConfigContextModel, CustomFieldModel):
     """
     """
     A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType,
     A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType,

+ 3 - 3
netbox/extras/api/serializers.py

@@ -14,7 +14,7 @@ from extras.constants import *
 from extras.models import (
 from extras.models import (
     ConfigContext, ExportTemplate, Graph, ImageAttachment, ObjectChange, ReportResult, Tag,
     ConfigContext, ExportTemplate, Graph, ImageAttachment, ObjectChange, ReportResult, Tag,
 )
 )
-from extras.utils import FeatureQuerySet
+from extras.utils import FunctionalityQueryset
 from tenancy.api.nested_serializers import NestedTenantSerializer, NestedTenantGroupSerializer
 from tenancy.api.nested_serializers import NestedTenantSerializer, NestedTenantGroupSerializer
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
 from users.api.nested_serializers import NestedUserSerializer
 from users.api.nested_serializers import NestedUserSerializer
@@ -33,7 +33,7 @@ from .nested_serializers import *
 
 
 class GraphSerializer(ValidatedModelSerializer):
 class GraphSerializer(ValidatedModelSerializer):
     type = ContentTypeField(
     type = ContentTypeField(
-        queryset=ContentType.objects.filter(FeatureQuerySet('graphs').get_queryset()),
+        queryset=ContentType.objects.filter(FunctionalityQueryset('graphs').get_queryset()),
     )
     )
 
 
     class Meta:
     class Meta:
@@ -69,7 +69,7 @@ class RenderedGraphSerializer(serializers.ModelSerializer):
 
 
 class ExportTemplateSerializer(ValidatedModelSerializer):
 class ExportTemplateSerializer(ValidatedModelSerializer):
     content_type = ContentTypeField(
     content_type = ContentTypeField(
-        queryset=ContentType.objects.filter(FeatureQuerySet('export_templates').get_queryset()),
+        queryset=ContentType.objects.filter(Q(FunctionalityQueryset('export_templates').get_queryset())),
     )
     )
     template_language = ChoiceField(
     template_language = ChoiceField(
         choices=TemplateLanguageChoices,
         choices=TemplateLanguageChoices,

+ 6 - 6
netbox/extras/models.py

@@ -22,7 +22,7 @@ from utilities.utils import deepmerge, render_jinja2
 from .choices import *
 from .choices import *
 from .constants import *
 from .constants import *
 from .querysets import ConfigContextQuerySet
 from .querysets import ConfigContextQuerySet
-from .utils import FeatureQuerySet
+from .utils import FunctionalityQueryset
 
 
 
 
 __all__ = (
 __all__ = (
@@ -59,7 +59,7 @@ class Webhook(models.Model):
         to=ContentType,
         to=ContentType,
         related_name='webhooks',
         related_name='webhooks',
         verbose_name='Object types',
         verbose_name='Object types',
-        limit_choices_to=FeatureQuerySet('webhooks'),
+        limit_choices_to=FunctionalityQueryset('webhooks'),
         help_text="The object(s) to which this Webhook applies."
         help_text="The object(s) to which this Webhook applies."
     )
     )
     name = models.CharField(
     name = models.CharField(
@@ -224,7 +224,7 @@ class CustomField(models.Model):
         to=ContentType,
         to=ContentType,
         related_name='custom_fields',
         related_name='custom_fields',
         verbose_name='Object(s)',
         verbose_name='Object(s)',
-        limit_choices_to=FeatureQuerySet('custom_fields'),
+        limit_choices_to=FunctionalityQueryset('custom_fields'),
         help_text='The object(s) to which this field applies.'
         help_text='The object(s) to which this field applies.'
     )
     )
     type = models.CharField(
     type = models.CharField(
@@ -471,7 +471,7 @@ class CustomLink(models.Model):
     content_type = models.ForeignKey(
     content_type = models.ForeignKey(
         to=ContentType,
         to=ContentType,
         on_delete=models.CASCADE,
         on_delete=models.CASCADE,
-        limit_choices_to=FeatureQuerySet('custom_links')
+        limit_choices_to=FunctionalityQueryset('custom_links')
     )
     )
     name = models.CharField(
     name = models.CharField(
         max_length=100,
         max_length=100,
@@ -519,7 +519,7 @@ class Graph(models.Model):
     type = models.ForeignKey(
     type = models.ForeignKey(
         to=ContentType,
         to=ContentType,
         on_delete=models.CASCADE,
         on_delete=models.CASCADE,
-        limit_choices_to=FeatureQuerySet('graphs')
+        limit_choices_to=FunctionalityQueryset('graphs')
     )
     )
     weight = models.PositiveSmallIntegerField(
     weight = models.PositiveSmallIntegerField(
         default=1000
         default=1000
@@ -582,7 +582,7 @@ class ExportTemplate(models.Model):
     content_type = models.ForeignKey(
     content_type = models.ForeignKey(
         to=ContentType,
         to=ContentType,
         on_delete=models.CASCADE,
         on_delete=models.CASCADE,
-        limit_choices_to=FeatureQuerySet('export_templates')
+        limit_choices_to=FunctionalityQueryset('export_templates')
     )
     )
     name = models.CharField(
     name = models.CharField(
         max_length=100
         max_length=100

+ 2 - 1
netbox/extras/tests/test_api.py

@@ -8,6 +8,7 @@ from rest_framework import status
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Platform, Rack, RackGroup, RackRole, Region, Site
 from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Platform, Rack, RackGroup, RackRole, Region, Site
 from extras.api.views import ScriptViewSet
 from extras.api.views import ScriptViewSet
 from extras.choices import *
 from extras.choices import *
+from extras.constants import GRAPH_MODELS
 from extras.models import ConfigContext, Graph, ExportTemplate, Tag
 from extras.models import ConfigContext, Graph, ExportTemplate, Tag
 from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
 from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
@@ -34,7 +35,7 @@ class AppTest(APITestCase):
         self.assertEqual(choices_to_dict(response.data.get('export-template:template_language')), TemplateLanguageChoices.as_dict())
         self.assertEqual(choices_to_dict(response.data.get('export-template:template_language')), TemplateLanguageChoices.as_dict())
 
 
         # Graph
         # Graph
-        content_types = ContentType.objects.filter(FeatureQuerySet('graphs').get_queryset())
+        content_types = ContentType.objects.filter(GRAPH_MODELS)
         graph_type_choices = {
         graph_type_choices = {
             "{}.{}".format(ct.app_label, ct.model): str(ct) for ct in content_types
             "{}.{}".format(ct.app_label, ct.model): str(ct) for ct in content_types
         }
         }

+ 3 - 2
netbox/extras/tests/test_filters.py

@@ -3,6 +3,7 @@ from django.test import TestCase
 
 
 from dcim.models import DeviceRole, Platform, Region, Site
 from dcim.models import DeviceRole, Platform, Region, Site
 from extras.choices import *
 from extras.choices import *
+from extras.constants import GRAPH_MODELS
 from extras.filters import *
 from extras.filters import *
 from extras.models import ConfigContext, ExportTemplate, Graph
 from extras.models import ConfigContext, ExportTemplate, Graph
 from tenancy.models import Tenant, TenantGroup
 from tenancy.models import Tenant, TenantGroup
@@ -17,7 +18,7 @@ class GraphTestCase(TestCase):
     def setUpTestData(cls):
     def setUpTestData(cls):
 
 
         # Get the first three available types
         # Get the first three available types
-        content_types = ContentType.objects.filter(FeatureQuerySet('graphs').get_queryset())[:3]
+        content_types = ContentType.objects.filter(GRAPH_MODELS)[:3]
 
 
         graphs = (
         graphs = (
             Graph(name='Graph 1', type=content_types[0], template_language=TemplateLanguageChoices.LANGUAGE_DJANGO, source='http://example.com/1'),
             Graph(name='Graph 1', type=content_types[0], template_language=TemplateLanguageChoices.LANGUAGE_DJANGO, source='http://example.com/1'),
@@ -31,7 +32,7 @@ class GraphTestCase(TestCase):
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
 
 
     def test_type(self):
     def test_type(self):
-        content_type = ContentType.objects.filter(FeatureQuerySet('graphs').get_queryset()).first()
+        content_type = ContentType.objects.filter(GRAPH_MODELS).first()
         params = {'type': content_type.pk}
         params = {'type': content_type.pk}
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
         self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
 
 

+ 24 - 30
netbox/extras/utils.py

@@ -22,61 +22,55 @@ def is_taggable(obj):
 
 
 class Registry:
 class Registry:
     """
     """
-    The registry is a place to hook into for data storage across components
+    Singleton object used to store important data
     """
     """
+    instance = None
 
 
-    def add_store(self, store_name, initial_value=None):
-        """
-        Given the name of some new data parameter and an optional initial value, setup the registry store
-        """
-        if not hasattr(Registry, store_name):
-            setattr(Registry, store_name, initial_value)
-
-registry = Registry()
+    def __new__(cls):
+        if cls.instance is not None:
+            return cls.instance
+        else:
+            cls.instance = super().__new__(cls)
+            cls.model_functionality_store = {f: collections.defaultdict(list) for f in EXTRAS_FUNCTIONALITIES}
+            return cls.instance
 
 
 
 
-#
-# Dynamic feature registration
-#
-
-class FeatureQuerySet:
+class FunctionalityQueryset:
     """
     """
     Helper class that delays evaluation of the registry contents for the functionaility store
     Helper class that delays evaluation of the registry contents for the functionaility store
     until it has been populated.
     until it has been populated.
     """
     """
 
 
-    def __init__(self, feature):
-        self.feature = feature
+    def __init__(self, functionality):
+        self.functionality = functionality
 
 
     def __call__(self):
     def __call__(self):
         return self.get_queryset()
         return self.get_queryset()
 
 
     def get_queryset(self):
     def get_queryset(self):
         """
         """
-        Given an extras feature, return a Q object for content type lookup
+        Given an extras functionality, return a Q object for content type lookup
         """
         """
         query = Q()
         query = Q()
-        #registry = Registry()
-        for app_label, models in registry.model_feature_store[self.feature].items():
+        registry = Registry()
+        for app_label, models in registry.model_functionality_store[self.functionality].items():
             query |= Q(app_label=app_label, model__in=models)
             query |= Q(app_label=app_label, model__in=models)
 
 
         return query
         return query
 
 
 
 
-registry.add_store('model_feature_store', {f: collections.defaultdict(list) for f in EXTRAS_FUNCTIONALITIES})
-
-
-def extras_features(features):
+def extras_functionality(functionalities):
     """
     """
-    Decorator used to register extras provided features to a model
+    Decorator used to register extras provided functionalities to a model
     """
     """
     def wrapper(model_class):
     def wrapper(model_class):
-        if isinstance(features, list) and features:
-            #registry = Registry()
-            model_class._extras_feature = []
-            for feature in features:
-                if feature in EXTRAS_FUNCTIONALITIES:
+        if isinstance(functionalities, list) and functionalities:
+            registry = Registry()
+            model_class._extras_functionality = []
+            for functionality in functionalities:
+                if functionality in EXTRAS_FUNCTIONALITIES:
+                    model_class._extras_functionality.append(functionality)
                     app_label, model_name = model_class._meta.label_lower.split('.')
                     app_label, model_name = model_class._meta.label_lower.split('.')
-                    registry.model_feature_store[feature][app_label].append(model_name)
+                    registry.model_functionality_store[functionality][app_label].append(model_name)
         return model_class
         return model_class
     return wrapper
     return wrapper