django-orchestra/orchestra/plugins/options.py

130 lines
3.9 KiB
Python
Raw Normal View History

from django.core.exceptions import ValidationError
2014-11-12 16:33:40 +00:00
from orchestra.utils.functional import cached
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
2015-03-04 21:06:16 +00:00
change_readonly_fileds = ()
2015-03-23 15:36:51 +00:00
plugin_field = None
2014-07-21 12:20:04 +00:00
def __init__(self, instance=None):
# Related model instance of this plugin
self.instance = instance
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
def get_plugin(cls, name):
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):
# don't evaluate p.verbose_name ugettext_lazy
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
def get_plugin_choices(cls):
choices = []
2014-10-11 16:21:51 +00:00
for plugin in cls.get_plugins():
verbose = plugin.get_verbose_name()
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
def get_change_readonly_fileds(cls):
return cls.change_readonly_fileds
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
@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
def get_plugin(cls, name):
# 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)