需要重复Flask形式,一种形式的多个实例class

need to repeat Flask form, multiple instances of one form class

注意:我知道我可以将表单代码重复 10 次来完成我想做的事情。我试图不重复代码并重复使用它 10 次,因为所有 10 种形式都是相同的。

我正在 raspberry pi 上构建一个带有烧瓶后端的自动化计时器到 运行,我这样做是为了能够像服务器一样访问 pi 并控制 pi。这是我正在尝试做的一个示例,我正在循环相同的代码并动态更改 10 个灌溉计时器中每一个的信息。 所以它是一个 html 页面,其中包含阀门 1 及其所有设置,然后是阀门 2....阀门3...等。 html 的示例在底部。

有一个构造函数并试图制作多个表单是行不通的,当我这样做时它一直在说

jinja2.exceptions.UndefinedError: 'webApp.forms.ValveForm object' has no     attribute 'valveName

这是对我不起作用的示例

class ValveForm(FlaskForm):
def __init__(self, name):
    valveName = StringField("Name", validators=[DataRequired(), Length(min=1, max=100)], default = name)
    valveNotes = TextAreaField("Notes", validators=[Length(max=300)])
    valveOnOff = SelectField("on/off", choices=[("True", "on"), ("False", "off")])
    valveCycleIrrigate = SelectField("cycle or irrigate", choices=[("cycle", "Cycle"), ("irrigate", "Irrigate")])

    valveIrrigationTime = TimeField("valveIrrigationTime")
    valveTimeHour = StringField("valveTimeHour")
    valveTimeMinute = StringField("valveTimeMinute")
    #valveTimeSecond = StringField("valveTimeSecond")

    cycleOnTimeHour = StringField("cycleOnTimeHour")
    cycleOnTimeMinute = StringField("cycleOnTimeMinute")
    cycleOnTimeSeconds = StringField("cycleOnTimeSecond")

    cycleOffTimeHour = StringField("cycleOffTimeHour")
    cycleOffTimeMinute = StringField("cycleOffTimeMinute")
    cycleOffTimeSeconds = StringField("cycleOffTimeSecond")

    blackoutStart = TimeField("blackoutStart")
    blackoutStop = TimeField("blackoutStop")

    selectAll = BooleanField("Select All")
    monday = BooleanField("monday")
    tuesday = BooleanField("tuesday")
    wednesday = BooleanField("wednesday")
    thursday = BooleanField("thursday")
    friday = BooleanField("friday")
    saturday = BooleanField("saturday")
    sunday = BooleanField("sunday")

    daysTuple = (selectAll, monday, tuesday, wednesday, thursday, friday, saturday, sunday)

它的工作原理如下,但当然这是行不通的。因为所有 10 个阀门都获得相同的信息。我正在尝试个性化每个信息。我需要在 class 中执行此操作,因为我需要为以前的设置插入默认值。通常人们不使用这样的表格,所以它给我带来了问题。

class ValveForm(FlaskForm):
    valveName = StringField("Name", validators=[DataRequired(), Length(min=1, max=100)], default = "something")
    valveNotes = TextAreaField("Notes", validators=[Length(max=300)])
    valveOnOff = SelectField("on/off", choices=[("True", "on"), ("False", "off")])
    valveCycleIrrigate = SelectField("cycle or irrigate", choices=[("cycle", "Cycle"), ("irrigate", "Irrigate")])

    valveIrrigationTime = TimeField("valveIrrigationTime")
    valveTimeHour = StringField("valveTimeHour")
    valveTimeMinute = StringField("valveTimeMinute")
    #valveTimeSecond = StringField("valveTimeSecond")

    cycleOnTimeHour = StringField("cycleOnTimeHour")
    cycleOnTimeMinute = StringField("cycleOnTimeMinute")
    cycleOnTimeSeconds = StringField("cycleOnTimeSecond")

    cycleOffTimeHour = StringField("cycleOffTimeHour")
    cycleOffTimeMinute = StringField("cycleOffTimeMinute")
    cycleOffTimeSeconds = StringField("cycleOffTimeSecond")

    blackoutStart = TimeField("blackoutStart")
    blackoutStop = TimeField("blackoutStop")

    selectAll = BooleanField("Select All")
    monday = BooleanField("monday")
    tuesday = BooleanField("tuesday")
    wednesday = BooleanField("wednesday")
    thursday = BooleanField("thursday")
    friday = BooleanField("friday")
    saturday = BooleanField("saturday")
    sunday = BooleanField("sunday")

    daysTuple = (selectAll, monday, tuesday, wednesday, thursday, friday, saturday, sunday)

这是 html 用于循环的阀门

{%extends "layout.html"%}

{%block body_content%}
{% for i in range(10) %}
    <h1>{{IrrigationValve.valveList[i].name}}</h1>
    <form method="POST" action="">
        {#{{ form.hidden_tag() }}#}
    <table class="table table-striped table-bordered">
        <tbody>
            <tr>
                <td>{{ formList[i].valveName.label(class="form-control-label") }} </td>
                <td>
                    <div class="form-group">

                        {% if formList[i].valveName.errors %}
                            {{ formList[i].valveName(class="form-control form-control-lg is-invalid") }}
                            <div class="invalid-feedback">
                                {% for error in valve.valveName.errors %}
                                    <span>{{ error }}</span>
                                {% endfor %}
                            </div>
                        {% else %}
                            {{ formList[i].valveName(class="form-control form-control-lg") }}
                        {% endif %}
                    </div>
                </td>
            </tr>
            <tr>
                <td>Notes</td>
                <td>
                    <div>
                        {{ formList[i].valveNotes(class="form-control form-control-lg") }}
                    </div>
                </td>
            </tr>
            <tr>
                <td>current state</td>
                <td>{{IrrigationValve.valveList[i].currentStateOn | trueFalseIndicator()}}</td>
            </tr>
            <tr>
                <td>on/off</td>
                <td>
                    <div class="form-group">
                        {{ formList[i].valveOnOff(class="form-control form-control-lg", value=IrrigationValve.valveList[i].currentStateOn) }}
                    </div>
                </td>
            </tr>
            <tr>
                <td>testing</td>
                <td>
                    <button type="submit" name="action" class="btn btn-danger" value="test">TEST</button>
                </td>
            </tr>
            <tr>
                <td>cycle or irrigate</td>
                <td>
                    <div class="form-group">
                        {{ formList[i].valveCycleIrrigate(class="form-control form-control-lg", value=IrrigationValve.valveList[i].cycleOrIrrigate) }}
                    </div>
                </td>
            </tr>
            <tr>
                <td>irrigation times</td>
                <td>
                    {% if not IrrigationValve.valveList[i].irrigationTimes %}
                        None 
                    {% else %}
                        {% for key, value in IrrigationValve.valveList[i].irrigationTimes.items() %} 
                            time: {{ key | strf_time_converter() }}  duration: {{ value | deltaToHrMinSec() }}
                            <button type="submit" name="action" id="{{ key }}" value="irrigation-time-delete" class="btn btn-danger">Delete</button>
                        {% endfor %} 
                    {% endif %}
                    <br><br>
                    <div class="form-group">
                        {{ formList[i].valveIrrigationTime() }}
                        <button type="submit" name="action" value="irrigation-time-add" class="btn btn-primary">Add</button>
                    </div>
                </td>
            </tr>
            <tr>
                <td>cycle on time</td>
                <td>
                    {%if not IrrigationValve.valveList[i].cycleOnTime%}
                        None<br><br>
                        <div>
                            <label>Hours</label>
                            {{ formList[i].cycleOnTimeHour() }} <br>
                            <label>Minutes</label>
                            {{ formList[i].cycleOnTimeMinute }} <br>
                            <label>Seconds</label>
                            {{ formList[i].cycleOnTimeSeconds }} <br>
                            <button type="submit" name="action" value="cycle-on-time-add" class="btn btn-primary">Add</button>
                        </div>
                    {%else%}
                        {{IrrigationValve.valveList[i].cycleOnTime | HrMinSec()}}
                        <button type="submit" name="action" value="cycle-on-time-delete" class="btn btn-primary">delete</button>
                    {%endif%}
                    <br><br>
                </td>
            </tr>
            <tr>
                <td>cycle off time</td>
                <td>
                    {%if not IrrigationValve.valveList[i].cycleOffTime%}
                        None<br><br>
                        <form>
                            <div>
                                <label>Hours</label>
                                {{ formList[i].cycleOffTimeHour }}<br>
                                <label>Minutes</label>
                                {{ formList[i].cycleOffTimeMinute }}<br>
                                <label>Seconds</label>
                                {{ formList[i].cycleOffTimeSeconds }}<br>
                                <button type="button" name="action" value="cycle-off-time-add" class="btn btn-primary">Add</button>
                            </div>
                        </form>
                    {%else%}
                        {{IrrigationValve.valveList[i].cycleOffTime | HrMinSec()}}
                        <button type="submit" name="action" value="cycle-off-time-delete" class="btn btn-primary">delete</button>
                    {%endif%}
                    <br><br>
                </td>
            </tr>
            <tr>
                <td>blackout start</td>
                <td>
                    {%if not IrrigationValve.valveList[i].blackoutStart%}
                        None
                        <br><br>
                        {{ formList[i].blackoutStart }}
                        <button type="submit" name="action" value="blackout-start-add" class="btn btn-primary">Add</button>
                    {%else%}
                        {{IrrigationValve.valveList[i].blackoutStart | strftimeConverter()}}
                        <button type="submit" name="action" value="blackout-start-delete" class="btn btn-primary">delete</button>
                    {%endif%}
                </td>
            </tr>
            <tr>
                <td>blackout stop</td>
                <td>
                    {%if not IrrigationValve.valveList[i].blackoutStop%}
                        None
                        <br><br>
                        {{ formList[i].blackoutStop }}
                        <button type="submit" name="action" value="blackout-stop-add" class="btn btn-primary">Add</button>
                    {%else%}
                        {{IrrigationValve.valveList[i].blackoutStop | strftimeConverter()}}
                        <button type="submit" name="action" value="blackout-stop-delete" class="btn btn-primary">delete</button>
                    {%endif%}
                </td>
            </tr>
            <tr>
                <td>days</td>
                <td>
                    {{ formList[i].selectAll }}{{ formList[i].selectAll.label }}<br>
                    <br>
                    {{ formList[i].monday }}{{ formList[i].monday.label }}<br>
                    {{ formList[i].tuesday }}{{ formList[i].tuesday.label }}<br>
                    {{ formList[i].wednesday }}{{ formList[i].wednesday.label }}<br>
                    {{ formList[i].thursday }}{{ formList[i].thursday.label }}<br>
                    {{ formList[i].friday }}{{ formList[i].friday.label }}<br>
                    {{ formList[i].saturday }}{{ formList[i].saturday.label }}<br>
                    {{ formList[i].sunday }}{{ formList[i].sunday.label }}<br>
                </td>
            </tr>
        </tbody>
    </table>
           <input class="btn-success btn-block btn-lg" type="submit" name="action" value="submit">
    </form>
{% endfor %}
{%endblock%}

这是 app.py

的一部分
@app.route("/valves", methods=["GET", "POST"])
def irrigationValve():
formList = [ValveForm(IrrigationValve.valveList[i].name) for i in range(10)]
for i in range(10):
    if formList[i].validate_on_submit():
        formList[i].setValve(irrigationValve.valveList[i])
        flash("changes saved", "success")
return render_template("valves.html", IrrigationValve=IrrigationValve, formList=formList)

这是动态 wtform 的另一个示例,SO 上有许多示例问题。

wtforms class 构造函数需要 class 级别的属性,而不是实例级别的属性,所以这有效:

class Form(FlaskForm):
    attribute = StringField()
    attribute2 = StringField()

虽然这不起作用:

class Form(FlaskForm):
    attribute2 = StringField()
    def __init__(self, arg):
        self.attribute = StringField(arg)

解决方案是构建动态 class 构造函数,如下所示:

def Form(arg):
    class TempForm(FlaskForm):
        attribute2 = StringField()
    setattr(TempForm, 'attribute', StringField(arg))
    return TempForm()

此函数接受一个参数,然后以适当的格式动态构造 class 对象和 returns 它的实例,并在您的路由中以相同的方式使用:

form = Form(arg)

编辑问题

然后您创建表单列表:

arg_list = ['one', 'two', ..., 'ten']
form_list = [Form(arg=arg_list[i]) for i in range(10)]

只有一种形式 - 此答案中没有任何部分建议编码 10 个单独的形式。