__init__.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. import collections
  2. import inspect
  3. from django.core.exceptions import ImproperlyConfigured
  4. from django.template.loader import get_template
  5. from extras.utils import registry
  6. from .signals import register_detail_page_content_classes
  7. class PluginTemplateContent:
  8. """
  9. This class is used to register plugin content to be injected into core NetBox templates.
  10. It contains methods that are overriden by plugin authors to return template content.
  11. The `model` attribute on the class defines the which model detail page this class renders
  12. content for. It should be set as a string in the form '<app_label>.<model_name>'.
  13. """
  14. model = None
  15. def __init__(self, obj):
  16. self.obj = obj
  17. def render(self, template, extra_context=None):
  18. """
  19. Convenience menthod for rendering the provided template name. The detail page object is automatically
  20. passed into the template context as `obj` but an additional context dictionary may be passed as `extra_context`.
  21. """
  22. context = {'obj': self.obj}
  23. if isinstance(extra_context, dict):
  24. context.update(extra_context)
  25. return get_template(template).render(context)
  26. def left_page(self):
  27. """
  28. Content that will be rendered on the left of the detail page view. Content should be returned as an
  29. HTML string. Note that content does not need to be marked as safe because this is automatically handled.
  30. """
  31. raise NotImplementedError
  32. def right_page(self):
  33. """
  34. Content that will be rendered on the right of the detail page view. Content should be returned as an
  35. HTML string. Note that content does not need to be marked as safe because this is automatically handled.
  36. """
  37. raise NotImplementedError
  38. def full_width_page(self):
  39. """
  40. Content that will be rendered within the full width of the detail page view. Content should be returned as an
  41. HTML string. Note that content does not need to be marked as safe because this is automatically handled.
  42. """
  43. raise NotImplementedError
  44. def buttons(self):
  45. """
  46. Buttons that will be rendered and added to the existing list of buttons on the detail page view. Content
  47. should be returned as an HTML string. Note that content does not need to be marked as safe because this is
  48. automatically handled.
  49. """
  50. raise NotImplementedError
  51. def register_content_classes():
  52. registry.plugin_template_content_classes = collections.defaultdict(list)
  53. responses = register_detail_page_content_classes.send('registration_event')
  54. for receiver, response in responses:
  55. if not isinstance(response, list):
  56. response = [response]
  57. for template_class in response:
  58. if not inspect.isclass(template_class):
  59. raise TypeError('Plugin content class {} was passes as an instance!'.format(template_class))
  60. if not issubclass(template_class, PluginTemplateContent):
  61. raise TypeError('{} is not a subclass of extras.plugins.PluginTemplateContent!'.format(template_class))
  62. if template_class.model is None:
  63. raise TypeError('Plugin content class {} does not define a valid model!'.format(template_class))
  64. registry.plugin_template_content_classes[template_class.model].append(template_class)
  65. def get_content_classes(model):
  66. if not hasattr(registry, 'plugin_template_content_classes'):
  67. register_content_classes()
  68. return registry.plugin_template_content_classes.get(model, [])