Проверка правильности вложенной Flask WTForm и удаление / удаление динамически именованной формы (поле формы) - PullRequest
0 голосов
/ 02 ноября 2018

Допустим, я создаю веб-опрос (собирая ответы на несколько вопросов) и что для этого я использую 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 для удаления специально именованного поля из мгновенного объекта формы, но, конечно, это не работает для динамически (переменных) именованных полей формы.

...