How to create chained selectfield in flask without refreshing the page?

前端 未结 2 2042

I am currently working on an address form using wtf, which contains Country, State, City..etc. The database is all set with FK.

class Country(db.Model):
            


        
相关标签:
2条回答
  • 2020-12-14 14:20

    If you want something dynamic on the client, there's no way around writing some JavaScript. Luckily it's not the 400+ lines you estimate. This example doesn't use WTForms, but that's not really important. The key part is sending the available choices as JSON, and dynamically changing the available options. Here's a single file runnable Flask app that demonstrates the basic idea.

    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()
    
    0 讨论(0)
  • 2020-12-14 14:25

    I had a similar problem recently and solved it using the idea from this answer.

    A minimal example could look like this:

    So, just two dropdowns, whereby the second depends on the selected value of the first one; all other elements on the page are not affected by this selection (here I only use one check box). Once the selection is made, the button below the dropdowns will trigger an action and the result can then again be displayed on the page (here, I only update the sentence below the button but of course you can also do more reasonable stuff), e.g. to:

    The HTML file looks like this (located in templates/index.html):

    <!DOCTYPE html>
    <html lang="en">
      <head>
        <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet">
      </head>
      <body>
        <div class="container">
          <div class="header">
            <h3 class="text-center text-muted">Dynamic dropdowns</h3>
          </div>
    
          <div>
            Check me and I don't change status when you select something below
          </div><br>
          <div>
            <input class="form-check-input" type="checkbox" value="" id="use_me">Select me
          </div><br><br>
    
          <div class="row">
            <div class="form-group col-xs-6">
              <label for="all_classes">Select a class</label>
              <select class="form-control" id="all_classes">
                {% for o in all_classes %}
                        <option value="{{ o }}">{{ o }}</option>
                {% endfor %}
              </select>
            </div>
            <div class="form-group col-xs-6">
              <label for="all_entries">Select an entry</label>
              <select class="form-control" id="all_entries">
                {% for o in all_entries %}
                        <option value="{{ o }}">{{ o }}</option>
                {% endfor %}
              </select>
            </div>
          </div>
    
          <div>
            <button type="button" id="process_input">Process selection!</button>
          </div><br><br>
          <div id="processed_results">
            Here we display some output based on the selection
          </div>
        </div>
        <script src="https://code.jquery.com/jquery-1.12.4.js" type="text/javascript"></script>
        <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
        <script type="text/javascript">
          $(document).ready(function() {
    
            $('#all_classes').change(function(){
    
              $.getJSON('/_update_dropdown', {
                selected_class: $('#all_classes').val()
    
              }).success(function(data) {
                    $('#all_entries').html(data.html_string_selected);
               })
            });
            $('#process_input').bind('click', function() {
    
                $.getJSON('/_process_data', {
                    selected_class: $('#all_classes').val(),
                    selected_entry: $('#all_entries').val(),
    
    
                }).success(function(data) {
                    $('#processed_results').text(data.random_text);
                })
              return false;
    
            });
          });
        </script>
      </body>
    </html>
    

    And the corresponding python script looks as follows:

    from flask import Flask, render_template, request, jsonify
    import json
    
    # Initialize the Flask application
    app = Flask(__name__)
    
    
    def get_dropdown_values():
    
        """
        dummy function, replace with e.g. database call. If data not change, this function is not needed but dictionary
        could be defined globally
        """
    
        class_entry_relations = {'class1': ['val1', 'val2'],
                                 'class2': ['foo', 'bar', 'xyz']}
    
        return class_entry_relations
    
    
    @app.route('/_update_dropdown')
    def update_dropdown():
    
        # the value of the first dropdown (selected by the user)
        selected_class = request.args.get('selected_class', type=str)
    
        # get values for the second dropdown
        updated_values = get_dropdown_values()[selected_class]
    
        # create the value sin the dropdown as a html string
        html_string_selected = ''
        for entry in updated_values:
            html_string_selected += '<option value="{}">{}</option>'.format(entry, entry)
    
        return jsonify(html_string_selected=html_string_selected)
    
    
    @app.route('/_process_data')
    def process_data():
        selected_class = request.args.get('selected_class', type=str)
        selected_entry = request.args.get('selected_entry', type=str)
    
        # process the two selected values here and return the response; here we just create a dummy string
    
        return jsonify(random_text="you selected {} and {}".format(selected_class, selected_entry))
    
    
    @app.route('/')
    def index():
    
        """
        Initialize the dropdown menues
        """
    
        class_entry_relations = get_dropdown_values()
    
        default_classes = sorted(class_entry_relations.keys())
        default_values = class_entry_relations[default_classes[0]]
    
        return render_template('index.html',
                               all_classes=default_classes,
                               all_entries=default_values)
    
    
    if __name__ == '__main__':
    
        app.run(debug=True)
    
    0 讨论(0)
提交回复
热议问题