2015-03-25 15:45:04 +00:00
|
|
|
from django.core.exceptions import ValidationError
|
|
|
|
|
2014-07-21 12:20:04 +00:00
|
|
|
|
|
|
|
class Plugin(object):
|
|
|
|
verbose_name = None
|
2014-10-11 12:43:08 +00:00
|
|
|
# Used on select plugin view
|
|
|
|
class_verbose_name = None
|
|
|
|
icon = None
|
2015-03-23 15:36:51 +00:00
|
|
|
change_form = None
|
|
|
|
form = None
|
|
|
|
serializer = None
|
2016-02-11 14:24:09 +00:00
|
|
|
change_readonly_fields = ()
|
2015-03-23 15:36:51 +00:00
|
|
|
plugin_field = None
|
2014-07-21 12:20:04 +00:00
|
|
|
|
2015-03-11 16:32:33 +00:00
|
|
|
def __init__(self, instance=None):
|
|
|
|
# Related model instance of this plugin
|
2016-05-08 09:35:18 +00:00
|
|
|
self.instance = instance
|
2016-05-07 20:09:05 +00:00
|
|
|
if self.form is None:
|
|
|
|
from .forms import PluginForm
|
|
|
|
self.form = PluginForm
|
|
|
|
super().__init__()
|
2015-03-11 16:32:33 +00:00
|
|
|
|
2014-07-21 12:20:04 +00:00
|
|
|
@classmethod
|
2014-11-12 16:33:40 +00:00
|
|
|
def get_name(cls):
|
2015-03-04 21:06:16 +00:00
|
|
|
return getattr(cls, 'name', cls.__name__)
|
2014-07-21 12:20:04 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get_plugins(cls):
|
|
|
|
return cls.plugins
|
|
|
|
|
|
|
|
@classmethod
|
2015-03-31 12:39:08 +00:00
|
|
|
def get(cls, name):
|
2015-03-10 11:46:48 +00:00
|
|
|
if not hasattr(cls, '_registry'):
|
|
|
|
cls._registry = {
|
|
|
|
plugin.get_name(): plugin for plugin in cls.get_plugins()
|
|
|
|
}
|
|
|
|
return cls._registry[name]
|
2014-07-21 12:20:04 +00:00
|
|
|
|
2014-10-11 16:21:51 +00:00
|
|
|
@classmethod
|
|
|
|
def get_verbose_name(cls):
|
2023-10-24 16:59:02 +00:00
|
|
|
# don't evaluate p.verbose_name gettext_lazy
|
2014-10-11 16:21:51 +00:00
|
|
|
verbose = getattr(cls.verbose_name, '_proxy____args', [cls.verbose_name])
|
|
|
|
if verbose[0]:
|
|
|
|
return cls.verbose_name
|
|
|
|
else:
|
2014-11-12 16:33:40 +00:00
|
|
|
return cls.get_name()
|
2014-10-11 16:21:51 +00:00
|
|
|
|
2014-07-21 12:20:04 +00:00
|
|
|
@classmethod
|
2015-03-31 12:39:08 +00:00
|
|
|
def get_choices(cls):
|
2014-07-21 12:20:04 +00:00
|
|
|
choices = []
|
2014-10-11 16:21:51 +00:00
|
|
|
for plugin in cls.get_plugins():
|
|
|
|
verbose = plugin.get_verbose_name()
|
2015-03-10 11:46:48 +00:00
|
|
|
choices.append(
|
|
|
|
(plugin.get_name(), verbose)
|
|
|
|
)
|
2014-10-11 16:21:51 +00:00
|
|
|
return sorted(choices, key=lambda e: e[1])
|
2015-03-04 21:06:16 +00:00
|
|
|
|
|
|
|
@classmethod
|
2016-02-11 14:24:09 +00:00
|
|
|
def get_change_readonly_fields(cls):
|
|
|
|
return cls.change_readonly_fields
|
2015-03-23 15:36:51 +00:00
|
|
|
|
2015-04-26 13:53:00 +00:00
|
|
|
@classmethod
|
|
|
|
def get_class_path(cls):
|
|
|
|
return '.'.join((cls.__module__, cls.__name__))
|
|
|
|
|
2015-03-23 15:36:51 +00:00
|
|
|
def clean_data(self):
|
|
|
|
""" model clean, uses cls.serizlier by default """
|
|
|
|
if self.serializer:
|
|
|
|
serializer = self.serializer(data=self.instance.data)
|
|
|
|
if not serializer.is_valid():
|
|
|
|
raise ValidationError(serializer.errors)
|
|
|
|
return serializer.data
|
|
|
|
return {}
|
|
|
|
|
|
|
|
def get_directive(self):
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def get_form(self):
|
|
|
|
self.form.plugin = self
|
|
|
|
self.form.plugin_field = self.plugin_field
|
|
|
|
return self.form
|
|
|
|
|
|
|
|
def get_change_form(self):
|
|
|
|
form = self.change_form or self.form
|
|
|
|
form.plugin = self
|
|
|
|
form.plugin_field = self.plugin_field
|
|
|
|
return form
|
|
|
|
|
|
|
|
def get_serializer(self):
|
|
|
|
self.serializer.plugin = self
|
|
|
|
return self.serializer
|
2014-07-21 12:20:04 +00:00
|
|
|
|
|
|
|
|
2014-11-13 15:34:00 +00:00
|
|
|
class PluginModelAdapter(Plugin):
|
|
|
|
""" Adapter class for using model classes as plugins """
|
|
|
|
model = None
|
|
|
|
name_field = None
|
2016-05-07 20:09:05 +00:00
|
|
|
form = None
|
2014-11-13 15:34:00 +00:00
|
|
|
|
2016-05-07 10:32:51 +00:00
|
|
|
def __init__(self, instance=None):
|
2016-05-07 20:09:05 +00:00
|
|
|
if self.form is None:
|
|
|
|
from .forms import PluginModelAdapterForm
|
|
|
|
self.form = PluginModelAdapterForm
|
2016-05-07 10:32:51 +00:00
|
|
|
super().__init__(instance)
|
|
|
|
|
2014-11-13 15:34:00 +00:00
|
|
|
@classmethod
|
|
|
|
def get_plugins(cls):
|
|
|
|
plugins = []
|
2015-03-27 19:50:54 +00:00
|
|
|
for related_instance in cls.model.objects.filter(is_active=True):
|
2014-11-13 15:34:00 +00:00
|
|
|
attributes = {
|
2015-03-27 19:50:54 +00:00
|
|
|
'related_instance': related_instance,
|
|
|
|
'verbose_name': related_instance.verbose_name
|
2014-11-13 15:34:00 +00:00
|
|
|
}
|
|
|
|
plugins.append(type('PluginAdapter', (cls,), attributes))
|
|
|
|
return plugins
|
|
|
|
|
2015-03-27 19:50:54 +00:00
|
|
|
@classmethod
|
2015-03-31 12:39:08 +00:00
|
|
|
def get(cls, name):
|
2015-03-27 19:50:54 +00:00
|
|
|
# don't cache, since models can change
|
|
|
|
for plugin in cls.get_plugins():
|
|
|
|
if name == plugin.get_name():
|
|
|
|
return plugin
|
|
|
|
|
2014-11-13 15:34:00 +00:00
|
|
|
@classmethod
|
|
|
|
def get_name(cls):
|
2015-03-27 19:50:54 +00:00
|
|
|
return getattr(cls.related_instance, cls.name_field)
|
2014-11-13 15:34:00 +00:00
|
|
|
|
|
|
|
|
2014-05-08 16:59:35 +00:00
|
|
|
class PluginMount(type):
|
|
|
|
def __init__(cls, name, bases, attrs):
|
2014-10-11 16:21:51 +00:00
|
|
|
if not attrs.get('abstract', False):
|
|
|
|
if not hasattr(cls, 'plugins'):
|
|
|
|
# This branch only executes when processing the mount point itself.
|
|
|
|
# So, since this is a new plugin type, not an implementation, this
|
|
|
|
# class shouldn't be registered as a plugin. Instead, it sets up a
|
|
|
|
# list where plugins can be registered later.
|
|
|
|
cls.plugins = []
|
|
|
|
else:
|
|
|
|
# This must be a plugin implementation, which should be registered.
|
|
|
|
# Simply appending it to the list is all that's needed to keep
|
|
|
|
# track of it later.
|
|
|
|
cls.plugins.append(cls)
|