让我们说我正在建立一个网络调查(收集对几个问题的回答),并且我正在使用一个由几个FormField(代表单个问题)组成的Flask WTForm来完成此任务:
from flask_wtf import FlaskForm
from wtforms.validators import InputRequired, Length, Email, EqualTo
class Survey_Form(FlaskForm):
name = 'Survey'
a_question = FormField(AForm)
b_question = FormField(BForm)
c_question = FormField(CForm)
...
z_question = FormField(ZForm)
class AForm(FlaskForm):
question = 'A_question'
responses = FormField(AResponses)
submit = SubmitField('Submit')
class AFormResponses(FlaskForm):
a_response = StringField('Response1:', validators=[InputRequired(), Length(min=8, max=10)])
b_response = StringField('Response2:', validators=[InputRequired(), Length(min=8, max=10)])
c_response = StringField('Response3:', validators=[InputRequired(), Length(min=8, max=10)])
class A_question(db.Model, Base):
__tablename__ = 'aquestion'
id = db.Column(db.Integer, primary_key=True)
type = db.Column(db.VARCHAR(8))
a_response = db.Column(db.VARCHAR(10))
b_response = db.Column(db.VARCHAR(12))
c_response = db.Column(db.VARCHAR(15))
@property
def serialize(self):
'''Return object data in easily serializable format'''
return {
"id" : self.id,
"type" : self.type,
"a_response" : self.a_response,
"b_response" : self.b_response,
"c_response" : self.c_response
}
def __init__(self,**kwargs):
if kwargs is None:
kwargs = {}
else:
for key, value in kwargs.items():
setattr(self,key,[value])
super(A_question,self).__init__()
def __str__(self):
return jsonify(self.serialize)
def __repr__(self):
return jsonify(self.serialize)
这是我的看法:
{% extends "main/layout.html" %}
{% block content %}
<div class="content-section">
<form method="POST" action="/survey">
{{ form.csrf_token }}
<fieldset class="form-group">
<legend class="border-bottom mb-4">
{{ form.name }}
</legend>
{% for item in form if item.widget.input_type != 'hidden' %}
{% if item.name not in ['blank','submit', 'completed_forms'] %}
<form method="POST" action="/survey/{{item.name.lower()}}">
{% endif %}
{{ item.csrf_token }}
<fieldset class="form-group">
{% if item.name != 'submit' %}
<legend class="border-bottom mb-4">
{{ item.question }}
</legend>
{% endif %}
{% for subitem in item.responses if subitem.widget.input_type != 'hidden' %}
<div class="form-group">
{{ subitem.label(class="form-control-label")}}
{% if subitem.errors %}
{{ subitem(class="form-control form-control-lg is-invalid") }}
<div class="invalid-feedback">
{% for error in subitem.errors %}
<span>{{ error }}</span>
{% endfor %}
</div>
{% else %}
{{ subitem(class="form-control form-control-lg") }}
{% endif %}
</div>
{% endfor %}
</fieldset>
<div class="form-group">
{{item.submit}}
</div>
</form>
{% endfor %}
</fieldset>
<div class="form-group">
{{ form.submit(class="btn btn-outline-info") }}
</div>
</form>
</div>
{% endblock content %}
当前,我正在利用“类型”功能实例化表单类对象并检查验证,从而在提交时动态处理各个表单:
(An example URL to hit this route would be: http://localmachine:8080/a/a_question)
@app.route("/<survey>/<question>", methods=['POST'])
def process_question(survey,question):
survey_form_name = survery.capitalize()+"_Form"
survey_form_type = type(survey_form_name, (FlaskForm,), {})
survey_form = survey_form_type()
form_name = question.capitalize()+"Form"
form_class = type(form_name, (FlaskForm,), {})
form = form_class()
if form.validate_on_submit():
{PROCESSING LOGIC}
flash('Responses to question {0} processed.'.format(form_name),'success')
else:
{ERROR PROCESSING LOGIC - just render form back to browser}}
这是我需要帮助的地方。而且我已经阅读了有关CSFRProtect的相关问题和评论-甚至尝试了禁用CSRF表单的初始化逻辑:
def __init__(self, *args, **kwargs):
kwargs['csrf_enabled'] = False
super(AFormResponses, self).__init__(*args, **kwargs)
但这似乎无法解决我的验证问题。
您可以看到子表单POST返回到路由示例url(http://localmachine:8080/a/a_question)的处理逻辑
我想念什么?
至于删除已处理字段(formfields),我确实了解如何使用setattr来设置类实例的动态命名属性,我可以使用它来将formfield设置为某种东西。有没有办法将其设置为null或可以禁用的字段? (我认为这可能是一个答案)
setattr(survey_form,question,FormField({SOME_DISABLED_FORM_OBJECT}))
我知道,如果我使用字典进行动态命名可能会更容易(并且可以说更安全)-但出于某种原因,我将不必这样做,
此外,我了解如何使用del form.field_name从即时表单对象中删除特定命名的字段,但是,这当然不适用于动态(可变)命名表单字段。