Python:无法动态地将属性设置为FlaskForm?
我想动态设置属性,这样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
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请求的视图函数的本地范围中。
我用关于构造函数的例子更新了这个问题,以澄清那里的区别。由于“我不知道Python的内部工作原理”,因此Python中的构造函数无法正常工作,或者Flask表单对库执行了一些操作以防止完成对象初始化。 Ofcouse,我们可以用'setattr'后面的很多方法来解决,但它并不能帮助我理解Flask或Python构造函数的情况。 – TomSawyer
如果你尝试在'setattr之后放置'super().__ init__',会发生什么? '?但是为什么你甚至想在'__init__'中使用'setattr'?您正在尝试构建一个在构造过程中更改其蓝图的对象。我甚至不知道这是否应该起作用。 – Feodoran
在setattr之后放置'super()'不起作用,它会给出错误'TypeError:'NoneType'对象不可迭代。在__init__里面的Setattr是很好的做法,可以在每种语言中工作,它有助于避免写更多的行来声明表单对象,我只需要:'form = MyForm(attrs)' – TomSawyer