jQuery autocomplete in Flask

11,739

Below is working JS/jQuery and Flask code:

@app.route('/autocomplete', methods=['GET'])
def autocomplete():
    search = request.args.get('q')
    query = db_session.query(Movie.title).filter(Movie.title.like('%' + str(search) + '%'))
    results = [mv[0] for mv in query.all()]
    return jsonify(matching_results=results)

HTML/jQuery:

<head>
<link href="//code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" rel="Stylesheet"></link>
<script src="//code.jquery.com/jquery-2.2.0.min.js"></script>
<script src="//code.jquery.com/ui/1.10.2/jquery-ui.js" ></script>

<script type="text/javascript">
$(function() {
    $("#autocomplete").autocomplete({
        source:function(request, response) {
            $.getJSON("{{url_for('autocomplete')}}",{
                q: request.term, // in flask, "q" will be the argument to look for using request.args
            }, function(data) {
                response(data.matching_results); // matching_results from jsonify
            });
        },
        minLength: 2,
        select: function(event, ui) {
            console.log(ui.item.value); // not in your question, but might help later
        }
    });
})

</script>
</head>
<body>
    <div>
        <input name="autocomplete" type="text" id="autocomplete" class="form-control input-lg"/>
    </div>
</body>

A bit of explanation is in order: 'q' is your search term argument name as defined in jQuery's $.getJSON ajax call. That's passed to flask, and picked up using request.args.get. The database query is constructed from that, and a list comprehension is used to construct the results. Note that with list comprehensions you don't initialize the list, nor do you use a for+append combination; one elegant line does everything.

Next, jsonify returns the list results wrapped as a dictionary with the key matching_results holding the results list. Do not be tempted to use json.dumps to return a list to your ajax call. See here why (TL/DR: security concerns).

Note also that i've deliberately changed some variable names so you could tell what script/flask function 'sees' which variable. E.g., the ajax call doesn't see the list results, it sees matching_results. And that's inside (now javascript's) data object.

To grab the list matching_results is the key for, use the pattern in the attached script. It's messier than simply sending a list, but more secure, and eventually will allow you to do more sophisticated things on the client-side using JS/jquery.

Finally, the select option prints the user's selection to the developer console, just for reference so you can actually respond to a user's selection.

For a more complete jquery-autocomplete example see the 'Load Data with AJAX' section here.

Share:
11,739
Steve
Author by

Steve

Test

Updated on July 27, 2022

Comments

  • Steve
    Steve almost 2 years

    Can't make jQuery autocomplete widget work with Flask framework. (http://jqueryui.com/autocomplete/#remote here is an example)
    In manage.py I got the following :

    @app.route('/autocomplete', methods=['GET'])
    def autocomplete():
        results = []
        search = request.args.get('autocomplete')
        for mv in db_session.query(Movie.title).filter(Movie.title.like('%' + str(search) + '%')).all():
            results.append(mv[0])
        return jsonify(json_list=results) 
    

    My index.html file:

        <head>
        ...
        <link href="http://code.jquery.com/ui/1.10.2/themes/smoothness/jquery-ui.css" rel="Stylesheet"></link>
        <script src="../static/js/jquery.js"></script>
        <script src="http://code.jquery.com/ui/1.10.2/jquery-ui.js" ></script>
    
    
        <script type="text/javascript">
        $(function() {
            $.ajax({
                url: '{{ url_for("autocomplete") }}'
                }).done(function (data) {
                    $('#autocomplete').autocomplete({
                        source: data.json_list,
                        minLength: 2
                    });
                });
            });
        </script>
        ...
        </head>
        <body>
        ...
           <div>
              <input name="autocomplete" type="text" id="autocomplete" class="form-control input-lg"/>
           </div>
        ...
        </body>
    

    Looks like dev tools in firefox don't return any errors. The terminal returns the following:

    "GET /autocomplete HTTP/1.1" 200 -
    "GET / HTTP/1.1" 200 -
    "GET /static/css/bootstrap.css HTTP/1.1" 304 -
    "GET /static/js/jquery.js HTTP/1.1" 304 -

    The widget just doesn't work. Since I don't know much about jQuery I can't figure out what causes the problem. Can anybody help me please ?

  • Steve
    Steve over 8 years
    Perfect answer! Thanks