Skip to content

Instantly share code, notes, and snippets.

@rluts
Last active November 6, 2018 11:19
Show Gist options
  • Save rluts/242196b2289b7bb1fac6ca2a63d09841 to your computer and use it in GitHub Desktop.
Save rluts/242196b2289b7bb1fac6ca2a63d09841 to your computer and use it in GitHub Desktop.
from django.db import models
from django.conf import settings
import pkgutil
import os
from importlib import import_module
from functools import partialmethod
class PluginField(models.CharField):
"""
1) Create 'plugins' path in your application directory
2) Declare Plugin class with 'name' property
3) in models.py:
class YourModel(models.Model):
plugin = PluginField()
4) Get Plugin instance:
obj = YourModel.objects.get(id=1)
instance = obj.get_plugin_instance()
https://gist.github.com/rluts/242196b2289b7bb1fac6ca2a63d09841
"""
description = 'Plugin field'
def __init__(self, plugins_path='plugins', *args, **kwargs):
self.plugins_path = plugins_path
kwargs['max_length'] = 255
super(PluginField, self).__init__(*args, **kwargs)
def deconstruct(self):
name, path, args, kwargs = super().deconstruct()
del kwargs["max_length"]
return name, path, args, kwargs
def _plugin_choices(self):
module_path = os.path.join(settings.BASE_DIR, self.app_label, self.plugins_path)
for pack in pkgutil.walk_packages([module_path]):
loader = import_module('.'.join([self.app_label, self.plugins_path, pack.name]))
yield (pack.name, loader.Plugin.name)
def _check_choices(self):
if hasattr(self, 'model'):
self.app_label = self.model._meta.app_label
self.choices = list(self._plugin_choices())
self.help_text = 'You can add new plugin to %s path' % os.path.join(self.app_label, self.plugins_path)
return super(PluginField, self)._check_choices()
def _get_loader(self, instance, *args):
loader = import_module('.'.join(
[self.model._meta.app_label, self.plugins_path, getattr(instance, self.attname)])
)
return loader.Plugin()
def contribute_to_class(self, cls, name, **kwargs):
super().contribute_to_class(cls, name, **kwargs)
instance = getattr(cls, self.attname)
setattr(cls, 'get_%s_instance' % self.name, partialmethod(self._get_loader, instance))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment