2010-09-18 35 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

相關問題