我目前正在使用wtf编写一个地址表,其中包含国家、州、市等。数据库都是用FK设置的。

class Country(db.Model):
    __tablename__ = 'countries'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    users = db.relationship('User', backref='countries', lazy='dynamic')
class City(db.Model):
    __tablename__ = 'cities'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    countries_id = db.Column(db.Integer, db.ForeignKey('countries.id'))

现在我试图实现链式selectfield排序效果,以优化用户体验。所需的效果是,在不离开或刷新页面的情况下,selectfield将根据上一个selectfield提取数据。
例如,用户在Country中选择Australia,那么State的第二个selectfield应该只包含Australia中的states。
我对这个问题做了一些研究,但没有一个令人满意的解决方案。以下是我发现的两个可能但不令人满意的解决方案。
1.使用jQuery插件,例如Chained。但是,这个插件需要逐行编码。如果我采用这种方法,至少还会有400多条线,这不是很蟒蛇。例如:
<select id="series" name="series">
  <option value="">--</option>
  <option value="series-3" class="bmw">3 series</option>
  <option value="series-5" class="bmw">5 series</option>
  <option value="series-6" class="bmw">6 series</option>
  <option value="a3" class="audi">A3</option>
  <option value="a4" class="audi">A4</option>
  <option value="a5" class="audi">A5</option>
</select>

2.使用Wtf的“带有动态选择值的选择字段”,这也是不可取的,因为它只根据前一个selectfield的默认值提取一次数据。例如:如果country的默认selectfield是Australia,那么state selectfield将只包含Australia内的states。当您将country selectfield改为America时,state selectfield仍然只包含澳大利亚境内的州。以下是wtf文档中列出的此方法的教程:
class UserDetails(Form):
    group_id = SelectField(u'Group', coerce=int)

def edit_user(request, id):
    user = User.query.get(id)
    form = UserDetails(request.POST, obj=user)
    form.group_id.choices = [(g.id, g.name) for g in Group.query.order_by('name')]

从上面的研究中,我假设令人满意的解决方案应该介于两者之间,并且它肯定应该包含一些Javascript来监视客户端活动,而不向服务器发送请求。有没有人有一个令人满意的解决方案的烧瓶框架?

最佳答案

如果你想在客户端上有动态的东西,就没办法写一些JavaScript。幸运的是这不是你估计的400多行。本例不使用WTForms,但这并不重要。关键部分是将可用选项作为JSON发送,并动态更改可用选项。这里有一个单文件可运行烧瓶应用程序,演示了基本思想。

from flask import Flask, render_template_string

app = Flask(__name__)

@app.route('/')
def index():
    systems = {
        'PlayStation': ['Spyro', 'Crash', 'Ico'],
        'N64': ['Mario', 'Superman']
    }

    return render_template_string(template, systems=systems)

template = """

<!doctype html>
<form>
    <select id="system">
        <option></option>
    </select>
    <select id="game"></select>
    <button type="submit">Play</button>
</form>
<script src="//code.jquery.com/jquery-2.1.1.min.js"></script>
<script>
    "use strict";

    var systems = {{ systems|tojson }};

    var form = $('form');
    var system = $('select#system');
    var game = $('select#game');

    for (var key in systems) {
        system.append($('<option/>', {'value': key, 'text': key}));
    }

    system.change(function(ev) {
        game.empty();
        game.append($('<option/>'));

        var games = systems[system.val()];

        for (var i in games) {
            game.append($('<option/>', {'value': games[i], 'text': games[i]}));
        }
    });

    form.submit(function(ev) {
        ev.preventDefault();
        alert("playing " + game.val() + " on " + system.val());
    });
</script>

"""

app.run()

10-06 08:14