2010-09-18 84 views
2

我正在使用Django,并希望能够将类存储在数据库中,以便像表单和模型这样的东西,以便我可以通过用户界面轻松地创建它们,因为它们只存储在数据库中,而不是常规文件。我对这件事并不十分了解,也不确定是否需要在python中使用exec或者有其他方法。我在这方面的搜索没有带来什么。Python,如何从存储在数据库中的类实例化类?

基本上,它只是我在做数据库调用并获取一个类的内容,然后我想实例化它。任何意见都赞赏如何最好地做这种事情。

编辑:为了回应类中存在的恶意__init__的想法,这些仅适用于形式或模型等通过验证课程内容进行严格控制的内容,在课堂上决不会有__init__而且这基本上是不可能的,因为我会验证服务器端的所有东西,把任何恶意的东西放在课堂上。

+1

如果__you__放在数据库中的类有一个'__init__'没关系。总的来说,__attacker__可以将一些其他类放在数据库中,__does__有一个'__init__'。另外'__init__'是一个红鲱鱼。它也可以覆盖模型的'save'或'clean'方法。 – aaronasterling 2010-09-18 20:33:10

+0

我明白,在实例化之前验证从数据库中获取的任何类是可能的,但这可能不值得麻烦,您可以解析文件并确保它符合某些标准等,但我认为其他方法vasil暗示会更好 – Rick 2010-09-19 07:14:54

回答

5

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

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

+0

好吧,我明白你的意思了。那么对此推荐的方法是什么呢?我想创建像用户可以创建表单(这是django中的类)的功能,像这样的事情..我应该让它直接写入文件,然后在数据库中跟踪它们? – Rick 2010-09-18 20:22:46

+0

哦,而且这些都没有__init__,因为它们只是表单类,并且已经通过严格验证控制了它们的内容,它不像他们可以创建自定义__init__ – Rick 2010-09-18 20:23:53

+1

@rick允许任意Python代码在您的数据库中找到要执行的请求是不安全的,无论您在那里进行验证,您都会错过某些东西。你可以创建一个类似于表单模型的表单模型,该表单模型将拥有一个外部模型,然后该模型将具有名称/标签/类型等,从这些模型中您将创建表单类,这需要一些关于表格如何在内部工作但是可行的知识。我建议你为此打开另一个问题。 – Vasil 2010-09-18 20:28:29

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) 
+0

感谢发布这个,我一定会看看..我认为Vasil做了一个好点,但我不知道我是否真的会在生产网站上使用这种方法,现在我正在考虑替代方案 – Rick 2010-09-19 07:12:24