验证Flask WTForm的嵌套以及动态命名表单(formfield)的删除/删除

时间:2018-11-02 17:18:29

标签: python flask flask-sqlalchemy flask-wtforms form-fields

让我们说我正在建立一个网络调查(收集对几个问题的回答),并且我正在使用一个由几个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从即时表单对象中删除特定命名的字段,但是,这当然不适用于动态(可变)命名表单字段。

0 个答案:

没有答案