【问题标题】:Python, how to instantiate classes from a class stored in a database?Python,如何从存储在数据库中的类实例化类?
【发布时间】:2010-09-18 20:13:26
【问题描述】:

我正在使用 Django,并且希望能够在数据库中存储表单和模型之类的类,以便我可以通过用户界面轻松创建它们,因为它们只是存储在数据库中,而不是常规的文件。我对此并不太了解,也不确定这是我需要在 python 中使用 exec 还是有其他方法的情况。我在这方面的搜索没有任何结果。

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

编辑:针对班级中恶意__init__ 的想法,这些仅适用于通过验证严格控制班级中的内容的表单或模型之类的东西,永远不会有__init__在课堂上,基本上是不可能的,因为我会验证服务器端的所有内容,在课堂上放置任何恶意内容。

【问题讨论】:

  • 放入数据库的类是否有__init__ 无关紧要。重点是攻击者可以将其他一些确实具有__init__的类放入数据库中。 __init__ 也是一个红鲱鱼。它也可以覆盖模型 saveclean 方法。
  • 我明白,可以在实例化之前验证从数据库中获取的任何类,但这可能不值得麻烦,您可以解析文件并确保它符合某些标准等但我认为 vasil 提到的另一种方法会更好

标签: python database django class


【解决方案1】:

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

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

【讨论】:

  • 好的,我明白你的意思了。那么推荐的方法是什么?我想创建类似 cms 的功能,用户可以在其中创建表单(这是 django 中的类)和类似的东西。我想我应该让它直接写文件然后在数据库中跟踪它们?
  • 哦,而且这些没有 init 因为它们只是表单类,并且通过大量验证已经可以控制其中可以包含的内容,它不是就像他们可以创建一个自定义 init
  • @rick 允许在您的数据库中找到的任意 python 代码按需执行是不安全的,无论您在那里进行任何验证,您都会错过一些东西。您可以创建类似于表单模型的东西,该模型将有一个包含外键的字段模型,然后字段模型将具有名称/标签/类型等,您可以从这些模型中动态创建表单类,这需要一些了解表单如何在内部工作,但可行。我建议你为此打开另一个问题。
  • 好的,我只是想为解决这个问题的方法找到正确的思路,你所说的从外键创建它等等听起来是个好方法,我会的如果我找不到足够的信息,请进一步研究并围绕此创建一个新问题,感谢您的帮助
  • @Rick 我认为如果您对问题的措辞不同,您可能会得到更有用的答案。诸如“我如何让用户使用 Django 创建表单”之类的东西,因为这似乎是您想要做的。
【解决方案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)

【讨论】:

  • 感谢您发布此内容,我一定会看看.. 我确实认为 Vasil 提出了一个很好的观点,所以我不知道我是否真的会在生产网站上使用这种方法我正在考虑替代方案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
  • 2017-11-11
  • 1970-01-01
  • 1970-01-01
  • 2012-01-06
  • 1970-01-01
相关资源
最近更新 更多