2017-10-09 68 views
0

我想动态设置属性,这样Python:无法动态地将属性设置为FlaskForm?

form = ModelForm(request.form) 

文件FlaskForm form.py

class ModelForm(FlaskForm): 
    def __init__(self, postData): 
     super(ModelForm, self).__init__() 
     for p in postData: 
      setattr(ModelForm, p, StringField(p, validators=[InputRequired()])) 

但它仅适用于运行,第一次运行的第二次合作,这不工作。

我真的不明白python构造函数是如何工作的。 由于这post,它说,由于

class A is not fully initialized when you do your setattr(A, p, v) there.

但在其他语言中,对象已经被构造完成之后创建的,它已经满级的变量,属性在构造函数中声明?

例如,它的工作原理可以打印a.key。那么烧瓶构造函数和这个有什么不同呢?

class A(object): 
    def __init__(self): 
     self.a = 'i am a accessor' 
     setattr(self, 'key', 'value') 

a = A() 
print a.a 
print a.key 

回答

0

class A is not fully initialized

手段,当你与form=ModelForm()创建类的第一个实例,你开始添加属性,当前是从实例化的类。我不知道,Python在内部是如何工作的。但既然你说这只能在第二次运行,我猜这个对象是第一次创建的,为这个类定义了所有的属性,然后执行__init__。所以新的属性被添加到最后。

换句话说:您正尝试更改之后的类定义您已经创建了它的一个实例。您需要添加您实例化的之前的所有属性,

现在你需要做的是:首先定义类没有任何动态字段。然后,在之后的类定义中,您将动态字段添加到循环中。

ModelForm = FlaskForm 
for p in postData: 
    setattr(ModelForm, p, StringField(p, validators=[InputRequired()])) 

或者,如果您需要添加类定义一些其他的东西:

class ModelForm(FlaskForm): 
    def foo(self): 
     return 'bar' 

for p in postData: 
    setattr(ModelForm, p, StringField(p, validators=[InputRequired()])) 

,然后在某处您的视图功能,您可以使用form = ModelForm(request.form)如常。

通常你会事先知道你需要什么字段。表单只是回答了GET请求中的内容。所以这应该没问题。 但是,也许你在客户端添加了一些JS的一些字段,而服务器还不知道(还)。在这种情况下,您可能会尝试将类定义放入处理POST请求的视图函数的本地范围中。

+0

我用关于构造函数的例子更新了这个问题,以澄清那里的区别。由于“我不知道Python的内部工作原理”,因此Python中的构造函数无法正常工作,或者Flask表单对库执行了一些操作以防止完成对象初始化。 Ofcouse,我们可以用'setattr'后面的很多方法来解决,但它并不能帮助我理解Flask或Python构造函数的情况。 – TomSawyer

+0

如果你尝试在'setattr之后放置'super().__ init__',会发生什么? '?但是为什么你甚至想在'__init__'中使用'setattr'?您正在尝试构建一个在构造过程中更改其蓝图的对象。我甚至不知道这是否应该起作用。 – Feodoran

+0

在setattr之后放置'super()'不起作用,它会给出错误'TypeError:'NoneType'对象不可迭代。在__init__里面的Setattr是很好的做法,可以在每种语言中工作,它有助于避免写更多的行来声明表单对象,我只需要:'form = MyForm(attrs)' – TomSawyer