Допустим, я создаю веб-опрос (собирая ответы на несколько вопросов) и что для этого я использую 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 %}
В настоящее время я динамически обрабатываю отдельные формы при отправке, используя функцию «type» для создания экземпляра объекта класса формы и проверки на валидацию:
(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)
Чего мне не хватает?
Что касается удаления обработанных полей (форм-полей), я понимаю, как использовать setattr для установки динамически именованного свойства экземпляра класса, который я мог бы использовать для установки поля формы чего-либо. Есть ли способ установить его на ноль или поле, которое можно отключить? (Я думаю, что это может быть ответом)
setattr(survey_form,question,FormField({SOME_DISABLED_FORM_OBJECT}))
Я знаю, что было бы проще (и, возможно, безопаснее), если бы я использовал словарь для динамического именования, - но по причинам, которые я не буду использовать, я должен сделать это таким образом.
Кроме того, я понимаю, как использовать del form.field_name для удаления специально именованного поля из мгновенного объекта формы, но, конечно, это не работает для динамически (переменных) именованных полей формы.