Python,如何从存储在数据库中的类实例化类?

时间:2010-09-18 20:13:27

标签: python database django class

我正在使用Django并且希望能够在数据库中存储类,例如表单和模型,这样我就可以通过用户界面轻松地创建它们,因为它们只是存储在数据库中而不是常规数据库中文件。我真的不太了解这一点,我不确定这是否需要在python中使用exec或者是否有其他方式。我对此的搜索并没有发现任何事情。

基本上,它只是我进行数据库调用并获取类的内容,然后我想实例化它。如何最好地做这类事情,对任何建议都表示赞赏。

编辑:为了回应类中恶意__init__的想法,这些仅用于形式或模型之类的东西,通过验证类中的内容来严格控制它,永远不会有{在课堂上{1}}基本上是不可能的,因为我会验证服务器端的所有内容,在课堂上放置任何恶意内容。

2 个答案:

答案 0 :(得分:5)

不要将代码存储在数据库中!!!

想象一下,一个带有恶意__init__方法的类在数据库中的“类库”中找到它。这意味着谁拥有对这些数据库表的写访问权限,就能够从您的Web服务器读取任何文件,甚至可以查看它的文件系统,因为它们能够在其上执行任何python代码。

答案 1 :(得分:2)

不要存储类本身,将导入路径存储为数据库中的字符串(例如'django.forms.CharField')

我开始为另一个项目做同样的事情,并保存了我本地存储库中的代码。为了解决安全问题,我将向允许的基类的字段构造函数添加一个参数。如果您确实实现了这一点,请告诉我,我很乐意拥有它。

helpers.py

def get_class_from_concrete_classpath(class_path):
    # Unicode will throw errors in the __import__ (at least in 2.6)
    class_path = str(class_path)

    mod_list = class_path.split('.')
    module_path = '.'.join(mod_list[:-1])
    class_name = mod_list[-1]

    base_mod = __import__(module_path, fromlist=[class_name,])
    return getattr(base_mod, class_name)


def get_concrete_name_of_class(klass):
    """Given a class return the concrete name of the class.

    klass - The reference to the class we're interested in.

    Raises a `TypeError` if klass is not a class.
    """

    if not isinstance(klass, (type, ClassType)):
        raise TypeError('The klass argument must be a class. Got type %s; %s' %
                        (type(klass), klass))

    return '%s.%s' % (klass.__module__, klass.__name__)

fields.py

class ClassFormField(forms.Field):
    def to_python(self, value):
        return get_concrete_name_of_class(value)

class ClassField(models.CharField):
    __metaclass__ = models.SubfieldBase

    """Field used for storing a class as a string for later retrieval"""

    MAX_LENGTH = 255
    default_error_messages = {
        'invalid': _(u'Enter a valid class variable.'),
    }

    def __init__(self, *args, **kwargs):
        kwargs['max_length'] = kwargs.get('max_length', ClassField.MAX_LENGTH)
        super(ClassField, self).__init__(*args, **kwargs)

    def get_prep_value(self, value):
        if isinstance(value, (basestring, NoneType)):
            return value

        return get_concrete_name_of_class(value)


    def to_python(self, value):
        if isinstance(value, basestring):
            return get_class_from_concrete_classpath(value)

        return value

    def formfield(self, **kwargs):    
        defaults = {'form_class' : ClassFormField}
        defaults.update(kwargs)
    return super(ClassField, self).formfield(**defaults)