【问题标题】:Getting Flask to alter selected value in HTML drop down让 Flask 更改 HTML 下拉列表中的选定值
【发布时间】:2017-05-07 04:34:57
【问题描述】:

我正在为家庭供暖控制系统编写原型前端,当用户从下拉框中选择房间和星期几时,我希望能够查询 Redis 数据库并检索当前设置每小时的温度,并使用它来设置温度下拉框中的选定值。然后用户可以更改一个或多个值并提交它们。我有提交和编写工作,只是想弄清楚设置选定的内容。

这是 HTML:

{% extends "bootstrap/base.html" %}
{% block title %}Setting Room Temperatures{% endblock %}
{% block navbar %}
<div class="navbar navbar-fixed-top">
  <!-- ... -->
</div>
{% endblock %}
{% block content %}
</head>
<body>
<h1>Room temperature configuration</h1>
<form action="{{ url_for('heating_config_form')}}" method="post" class="form-inline"> 
<div class="form-group">
<label for="roomselect">Room:</label>
<select class="form-control" name="roomselect">
  <option value="dining">Dining</option>
  <option value="kitchen">Kitchen</option>
  <option value="lounge">Lounge</option>
  <option value="study">Study</option>
 </select>
</div>
<br>
<br>
<div class="form-group">
<label for="dayselect">Day  :</label>
<select class="form-control" name="dayselect">
  <option value="monday">Monday</option>
  <option value="tuesday">Tuesday</option>
  <option value="wednesday">Wednesday</option>
  <option value="thursday">Thursday</option>
  <option value="friday">Friday</option>
  <option value="saturday">Saturday</option>
  <option value="sunday">Sunday</option>
</select>
</div>
<br>
<br>
 <div class="form-group">
 <label for="1AM">1AM :</label>
 <select class="form-control" name="1AM">
   <option value="5">5</option>
   <option value="6">6</option>
</select>
<label for="2AM">2AM :</label>
<select class="form-control" name="2AM">
  <option value="5">5</option>
  <option value="6">6</option>
</select>
</div>
<br>
<br>
<button type="submit" value="submitted" name="update">Update temperature </button><br>
<br>
</form>
<br>
</body></html>
{% endblock %}<html><head>

这是 Python Flask 代码

from flask import Flask
from flask import request
from flask import render_template
from flask_bootstrap import Bootstrap
import redis

app = Flask(__name__)
app.debug = True
bootstrap = Bootstrap(app)

db = redis.Redis('localhost')

@app.route('/', methods=['GET','POST'])
def heating_config_form():
    error=""
    if request.method == 'POST' and request.form['update'] == 'submitted':
        Room = (request.form.get('roomselect'))
        Day = (request.form.get('dayselect'))
        AM1 = (request.form.get('1AM'))
        AM2 = (request.form.get('2AM'))
        key = (Room + "_" + Day)
        db.hset(key, "1:00", AM1)
        db.hset(key, "2:00", AM2)
        return render_template('set-room-tempv5.html')
    else :
        return render_template('set-room-tempv5.html')
if __name__ == '__main__':
    app.run(host='0.0.0.0', debug=True)

我知道可能有更好的方法来解决这个问题(WTForms?),但我想获得一个我理解的简单设置界面,这样我就可以在开发更好的前端的同时对系统进行原型设计,因为我是 Flask 的新手并且不希望整个供暖系统依赖于我的能力:)

将温度添加到数据库可以正常工作,这是 redis-cli 监视器的典型监视器输出

127.0.0.1:6379> monitor
OK
1482336847.287342 [0 127.0.0.1:34180] "HSET" "kitchen_tuesday" "1:00" "5"
1482336847.288042 [0 127.0.0.1:34180] "HSET" "kitchen_tuesday" "2:00" "5"

我在想也许像以下上下文处理器这样的东西可以提供帮助?

@app.context_processor
def utility_processor():
    def retrieve_temp(sroom, sday, stime):
        skey= (sroom + "_" + sday)
        stemp = db.hget(skey, stime)
        return stemp
    return dict(retrieve_temp=retrieve_temp)

这将使函数retrieve_temp 可用于所有模板 - 我想!

然后不知何故,一旦模板被渲染,默认房间和日期用于设置时间下拉菜单上的“选定”选项,然后每次移动房间和日期下拉菜单时,同样的情况再次发生。

因此,如果默认值是用餐和星期一,因为它们是选择选项中的第一个,则将检索凌晨 1 点和凌晨 2 点的温度并将其设置为这些下拉菜单的选择(有更多的时间和更多的临时工,这些已被删除为简洁起见)。如果房间和/或日期发生变化,它会再次发生。

【问题讨论】:

  • 澄清......你想要的是有一组选择框,其中第二个只显示基于第一个选择的值?并且每次第一个框中的选择发生变化时,您希望 ping 数据库以获取适当的选择以填充第二个选择?
  • 这是一个公平的总结 PJ。一旦用户选择了房间和日期,就会从该房间/天组合的数据库中检索每小时的适当温度设置,并填充适当的下拉选择。例如,如果用户选择休息室和星期二,则将查询数据库以获取当天每个小时的所有当前温度设置,以便可以为这些时间设置选择。我认为可以更容易选择一个页面/天,一旦提交,一个新页面显示了从DB span>检索的相应选择的下拉框

标签: python-3.x flask


【解决方案1】:

好的 - 所以在我给你信息以解决问题之前,我只是想确定你的问题。您在 cmets 中概述的替代方法是使其工作的最简单方法(例如,中间页面进行第一次选择)。

请务必记住,任何 python 或 jinja2 代码只会执行 1 次。 Jinja2 使用一些逻辑来呈现 HTML 输出,然后 Flask 以静态 HTML 页面响应浏览器,因此您可以使用 context_processor 将特定逻辑传递给 jinja2,但是一旦 Flask 呈现页面,任何交互都需要管理通过javascript。

您似乎正在使用 Bootstrap,其中包括 jQuery javascript 库。 jQuery 很棒(在我看来),因为它在如何与 DOM 交互和操作 DOM 方面为您处理了一些浏览器怪癖(例如,文档对象模型,javascript 对 HTML 元素的表示)。

因此,如果您想动态填充第二个选择,您可以设计一些代码以异步方式(例如,无需发出另一个 HTTP 请求或“重新加载”页面)将数据从浏览器发送到 Flask 端点以获取所需的选项然后更新前端。我给你举个例子:

HTML 看起来像这样(我只是添加 ID。for 标记应该引用 ID 字段,而不是名称,它也使 javascript 选择更容易):

<div class="form-group">
    <label for="roomselect">Room:</label>
    <select class="form-control" name="roomselect" id="roomselect">
        <option value="dining">Dining</option>
        <option value="kitchen">Kitchen</option>
        <option value="lounge">Lounge</option>
        <option value="study">Study</option>
    </select>
</div>

<div class="form-group">
    <label for="dayselect">Day:</label>
    <select class="form-control" name="dayselect" id="dayselect">
        <option value="monday">Monday</option>
        <option value="tuesday">Tuesday</option>
        <option value="wednesday">Wednesday</option>
        <option value="thursday">Thursday</option>
        <option value="friday">Friday</option>
        <option value="saturday">Saturday</option>
        <option value="sunday">Sunday</option>
    </select>
</div>

<div class="form-group">
    <label for="1AM">1AM:</label>
    <select class="form-control" name="1AM" id="1AM">
        <option value="5">5</option>
        <option value="6">6</option>
    </select>
    <label for="2AM">2AM:</label>
    <select class="form-control" name="2AM" id="2AM" disabled>
        <option value="5">5</option>
        <option value="6">6</option>
    </select>
</div>

然后,您需要添加一个 javascript 事件侦听器和 AJAX 方法,通常您在 HTML 正文的底部或链接文件中执行此操作:

<script charset="utf-8" type="text/javascript">
    // this is called a javascript closure. it also wont run the code until the page is finished loading
    // and it protects the scope of your variables from other code you may later add to the page
    $(function() {
        var select_room = $('#roomselect'),
            select_day = $('#dayselect'),
            select_1am = $('#1am'),
            select_2am = $('#2am');

        select_room.on('change', function() {
            // fires when room selection changes
            getUpdatedSettings();
        });

        select_day.on('change', function() {
            // fires when day selection changes
            getUpdatedSettings();
        });

        function getUpdatedSettings() {
            // data to send back to the server
            var send = {
                room: select_room.val(),
                day: select_day.val()
            };

            // make the selections disabled while fetching new data
            select_1am.attr('disabled', true);
            select_2am.attr('disabled', true);

            $.getJSON("/_get_updated_settings", send, function(response) {
                // this send the room and the day select vals to the URL specified
                // we will need to add a handler for this in Flask

                // for the purpose of the example I am assuming the response will be
                // a JSON object that has a dictionary of elements ("am_1" and "am_2")
                // each of which is a list of values for the selects....

                console.log(response); // good for QA!

                // populate 1am
                select_1am.empty();
                $.each(response.am_1, function (index, value) {
                    select_1am.append(
                    $('<option>', {
                        value: value,
                        text: value
                    }, '</option>'))
                });

                // populate 2am
                select_2am.empty();
                $.each(response.am_2, function (index, value) {
                    select_2am.append(
                    $('<option>', {
                        value: value,
                        text: value
                    }, '</option>'))
                });

                // remove disabled now
                select_1am.removeAttr('disabled');
                select_2am.removeAttr('disabled');
            });
        }

    });
</script>

现在,你需要添加一些 Flask 逻辑来处理这个 AJAX 请求:

from flask import jsonify

@app.route('/_get_updated_settings')
def get_updated_settings():
    # good for debug, make sure args were sent
    print request.args
    day = request.args.get('day', 'default_if_none')
    room = request.args.get('room', 'default_if_none')
    key = (room + "_" + day)
    output = {}
    # I have no idea what this returns...just doing a list generator here assuming we get a list of values
    output['am_1'] = [x for x in db.hget(skey, '1am')]
    output['am_2'] = [x for x in db.hget(skey, '1am')]
    return jsonify(output)

哈...结果比我预期的要长一点,但这至少应该为您提供一个稻草人来获得这样的功能。 Javascript 确实提供了更好的用户体验,但您通常可以通过使用一系列填充静态页面的中间表单来完成同样的事情。

【讨论】:

  • 感谢您的宝贵时间,抱歉花了一段时间才回复,但我想先看看能否让它工作或有问题。我在使用 jquery 时遇到了可变范围问题,因此在一位比我更精通网络的同事的帮助下,我们解决了这些问题。但是现在 jquery 脚本不是由 select 事件触发的。如果我重新加载页面,我会在与脚本相关联的烧瓶控制台上得到 304,这是合乎逻辑的,并且在浏览器控制台中,如果更改,我会得到“reflow:0.43ms function n.event.fix, jquery.min.js line 3”下拉列表中的选择。所以我还在调试中。
猜你喜欢
  • 2015-05-12
  • 2012-01-25
  • 1970-01-01
  • 2013-04-12
  • 1970-01-01
  • 2021-12-28
  • 1970-01-01
  • 2014-09-08
相关资源
最近更新 更多