我正在使用Django并且希望能够在数据库中存储类,例如表单和模型,这样我就可以通过用户界面轻松地创建它们,因为它们只是存储在数据库中而不是常规数据库中文件。我真的不太了解这一点,我不确定这是否需要在python中使用exec或者是否有其他方式。我对此的搜索并没有发现任何事情。
基本上,它只是我进行数据库调用并获取类的内容,然后我想实例化它。如何最好地做这类事情,对任何建议都表示赞赏。
编辑:为了回应类中恶意__init__
的想法,这些仅用于形式或模型之类的东西,通过验证类中的内容来严格控制它,永远不会有{在课堂上{1}}基本上是不可能的,因为我会验证服务器端的所有内容,在课堂上放置任何恶意内容。
答案 0 :(得分:5)
不要将代码存储在数据库中!!!
想象一下,一个带有恶意__init__
方法的类在数据库中的“类库”中找到它。这意味着谁拥有对这些数据库表的写访问权限,就能够从您的Web服务器读取任何文件,甚至可以查看它的文件系统,因为它们能够在其上执行任何python代码。
答案 1 :(得分:2)
不要存储类本身,将导入路径存储为数据库中的字符串(例如'django.forms.CharField')
我开始为另一个项目做同样的事情,并保存了我本地存储库中的代码。为了解决安全问题,我将向允许的基类的字段构造函数添加一个参数。如果您确实实现了这一点,请告诉我,我很乐意拥有它。
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__)
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)