Rework template content registration to work like menu items

This commit is contained in:
Jeremy Stretch 2020-03-25 16:06:00 -04:00
parent 1d9fbeed81
commit 68a0e76ca6
3 changed files with 27 additions and 42 deletions

View File

@ -6,10 +6,10 @@ from django.template.loader import get_template
from django.utils.module_loading import import_string
from extras.registry import registry
from .signals import register_detail_page_content_classes
# Initialize plugin registry stores
registry['plugin_template_content_classes'] = collections.defaultdict(list)
registry['plugin_nav_menu_links'] = {}
@ -48,10 +48,18 @@ class PluginConfig(AppConfig):
# Default integration paths. Plugin authors can override these to customize the paths to
# integrated components.
template_content_classes = 'template_content.template_content_classes'
menu_items = 'navigation.menu_items'
def ready(self):
# Register template content
try:
class_list = import_string(f"{self.__module__}.{self.template_content_classes}")
register_template_content_classes(class_list)
except ImportError:
pass
# Register navigation menu items (if defined)
try:
menu_items = import_string(f"{self.__module__}.{self.menu_items}")
@ -67,7 +75,7 @@ class PluginConfig(AppConfig):
class PluginTemplateContent:
"""
This class is used to register plugin content to be injected into core NetBox templates.
It contains methods that are overriden by plugin authors to return template content.
It contains methods that are overridden by plugin authors to return template content.
The `model` attribute on the class defines the which model detail page this class renders
content for. It should be set as a string in the form '<app_label>.<model_name>'.
@ -123,36 +131,20 @@ class PluginTemplateContent:
raise NotImplementedError
def register_content_classes():
def register_template_content_classes(class_list):
"""
Helper method that populates the registry with all template content classes that have been registered by plugins
Register a list of PluginTemplateContent classes
"""
registry['plugin_template_content_classes'] = collections.defaultdict(list)
# Validation
for template_content_class in class_list:
if not inspect.isclass(template_content_class):
raise TypeError('Plugin content class {} was passes as an instance!'.format(template_content_class))
if not issubclass(template_content_class, PluginTemplateContent):
raise TypeError('{} is not a subclass of extras.plugins.PluginTemplateContent!'.format(template_content_class))
if template_content_class.model is None:
raise TypeError('Plugin content class {} does not define a valid model!'.format(template_content_class))
responses = register_detail_page_content_classes.send('registration_event')
for receiver, response in responses:
if not isinstance(response, list):
response = [response]
for template_class in response:
if not inspect.isclass(template_class):
raise TypeError('Plugin content class {} was passes as an instance!'.format(template_class))
if not issubclass(template_class, PluginTemplateContent):
raise TypeError('{} is not a subclass of extras.plugins.PluginTemplateContent!'.format(template_class))
if template_class.model is None:
raise TypeError('Plugin content class {} does not define a valid model!'.format(template_class))
registry['plugin_template_content_classes'][template_class.model].append(template_class)
def get_content_classes(model):
"""
Given a model string, return the list of all registered template content classes.
Populate the registry if it is empty.
"""
if 'plugin_template_content_classes' not in registry:
register_content_classes()
return registry['plugin_template_content_classes'].get(model, [])
registry['plugin_template_content_classes'][template_content_class.model].append(template_content_class)
#

View File

@ -3,7 +3,9 @@ from django.dispatch.dispatcher import NO_RECEIVERS
class PluginSignal(django.dispatch.Signal):
"""
FUTURE USE
"""
def _sorted_receivers(self, sender):
orig_list = self._live_receivers(sender)
sorted_list = sorted(
@ -24,11 +26,3 @@ class PluginSignal(django.dispatch.Signal):
response = receiver(signal=self, sender=sender, **kwargs)
responses.append((receiver, response))
return responses
"""
This signal collects template content classes which render content for object detail pages
"""
register_detail_page_content_classes = PluginSignal(
providing_args=[]
)

View File

@ -1,9 +1,7 @@
from django import template as template_
from django.template.loader import get_template
from django.utils.safestring import mark_safe
from extras.plugins import get_content_classes
from extras.registry import registry
register = template_.Library()
@ -15,7 +13,8 @@ def _get_registered_content(obj, method, context):
"""
html = ''
plugin_template_classes = get_content_classes(obj._meta.label_lower)
model_name = obj._meta.label_lower
plugin_template_classes = registry['plugin_template_content_classes'].get(model_name, [])
for plugin_template_class in plugin_template_classes:
plugin_template_renderer = plugin_template_class(obj, context)
try: