28

I'm making a website with Flask and I'd like to be able to execute python code using data from the page. I know that I can simply use forms but it's a single page that is continually updated as it receives user input and it'd be a massive pain in the ass to have it reload the page every time something happens. I know I can do {{ function() }} inside the javascript but how do I do {{ function(args) }} inside the javascript using js variables? So far the only thing I can think of is to update an external database like MongoDB with the js then use Python to read from that, but this process will slow down the website quite a lot.

The jQuery needs to get a list of dictionary objects from the Python function which can then be used in the html. So I need to be able to do something like:

JS:

var dictlist = { getDictList(args) };
dictlist.each(function() {
    $("<.Class>").text($(this)['Value']).appendTo("#element");
});

Python:

def getDictList(args):
    return dictlistMadeFromArgs
Ztyx
  • 14,100
  • 15
  • 78
  • 114
Sneaky Beaver
  • 705
  • 2
  • 8
  • 15

3 Answers3

68

To get data from Javascript to Python with Flask, you either make an AJAX POST request or AJAX GET request with your data.

Flask has six HTTP methods available, of which we only need the GET and POST. Both will take jsdata as a parameter, but get it in different ways. That's how two completely different languages in two different environments like Python and Javascript exchange data.

First, instantiate a GET route in Flask:

@app.route('/getmethod/<jsdata>')
def get_javascript_data(jsdata):
    return jsdata

or a POST one:

@app.route('/postmethod', methods = ['POST'])
def get_post_javascript_data():
    jsdata = request.form['javascript_data']
    return jsdata

The first one is accessed by /getmethod/<javascript_data> with an AJAX GET as follows:

$.get( "/getmethod/<javascript_data>" );

The second one by using an AJAX POST request:

$.post( "/postmethod", {
    javascript_data: data 
});

Where javascript_data is either a JSON dict or a simple value.

In case you choose JSON, make sure you convert it to a dict in Python:

json.loads(jsdata)[0]

Eg.

GET:

@app.route('/getmethod/<jsdata>')
def get_javascript_data(jsdata):
    return json.loads(jsdata)[0]

POST:

@app.route('/postmethod', methods = ['POST'])
def get_post_javascript_data():
    jsdata = request.form['javascript_data']
    return json.loads(jsdata)[0]

If you need to do it the other way around, pushing Python data down to Javascript, create a simple GET route without parameters that returns a JSON encoded dict:

@app.route('/getpythondata')
def get_python_data():
    return json.dumps(pythondata)

Retrieve it from JQuery and decode it:

$.get("/getpythondata", function(data) {
    console.log($.parseJSON(data))
})

The [0] in json.loads(jsdata)[0] is there because when you decode a JSON encoded dict in Python, you get a list with the single dict inside, stored at index 0, so your JSON decoded data looks like this:

[{'foo':'bar','baz':'jazz'}] #[0: {'foo':'bar','baz':'jazz'}]

Since what we need is the just the dict inside and not the list, we get the item stored at index 0 which is the dict.

Also, import json.

Alper Turan
  • 1,220
  • 11
  • 24
  • What is the 'test.php' file supposed to be? – Sneaky Beaver May 01 '15 at 14:23
  • 2
    @SneakyBeaver Sorry a typo, fixed. – Alper Turan May 01 '15 at 14:25
  • 2
    So if I went the post route, I could do something like var dictlist = $.post( "/postmethod", { javascript_data: data } ); and have the python return a dict, and be able to use dictlist as a normal array of dict objects inside the js? Also what does the [0] after (jsdata) do? – Sneaky Beaver May 01 '15 at 14:31
  • 3
    That's the other way around. If *what you need* is to push Python data down to Javascript you just need a GET route without parameters that returns a dictionary encoded in JSON `json.dumps(dictlist)` and retrieve it in JQuery like `$.get( "/getmethod", function( data ){ console.log( data ) })`. Altough, if you're doing this frequently, I'd suggest using [Long Polling](http://en.wikipedia.org/wiki/Push_technology) or [Server Sent Events](http://www.w3schools.com/html/html5_serversentevents.asp). – Alper Turan May 01 '15 at 14:41
  • 1
    Gotcha. I need to send a string from js to python and then a dictionary derived from another function from python to js. Do I need to do anything special inside the JS to convert the JSON or is JSON just the way JS stuff is encoded? Sorry I'm pretty new to all this, up until about a week ago the only language I used was Python and everything I did was pretty simple. – Sneaky Beaver May 01 '15 at 14:44
  • 3
    Yep, I forgot that step. You have to decode the JSON with [$.parseJSON(data)](https://api.jquery.com/jquery.parsejson/) to use it as a Javascript object, or it won't work. – Alper Turan May 01 '15 at 14:47
  • 1
    @AlperTuran Good explanation I have been trying to solve something like this all day. A quick question. How would I display the data (when selecting from mysql) pushing from python to my template? – mp252 May 09 '17 at 17:20
  • 1
    I have used a post method, but it is giving an error POST http://127.0.0.1:5000/postmethod 400 (BAD REQUEST). – Ajoe Jul 10 '17 at 11:07
  • If we use the non-slim version of jquery ``` ``` in our base.HTML and later follows your code, this becomes so powerful! Thanks a lot @AlperTuran ! – Corina Roca Jan 30 '21 at 14:32
5

.html

... id="clickMe" onclick="doFunction();">

.js

    function doFunction()
    {
        const name = document.getElementById("name_").innerHTML

        $.ajax({
            url: '{{ url_for('view.path') }}',
            type: 'POST',
            data: {
                name: name
            },
            success: function (response) {
            },
            error: function (response) {
            }
        });

    };

.py

@app.route("path", methods=['GET', 'POST'])
def view():
    name = request.form.get('name')
    ...
Ayse
  • 576
  • 4
  • 13
1

im new in coding, but you can try this:
index.html

<script>
var w = window.innerWidth;
var h = window.innerHeight;
document.getElementById("width").value = w;
document.getElementById("height").value = h;
</script>
<html>
  <head>
    <!---Your Head--->
  </head>
  <body>
    <form method = "POST" action = "/data">
      <input type = "text" id = "InputType" name = "Text">
      <input type = "hidden" id = "width" name = "Width">
      <input type = "hidden" id = "height" name = "Height">
      <input type = "button" onclick = "myFunction()">
    </form>
  </body>
</html>

.py
from flask import Flask, request
app = Flask(__name__)
html = open("index.html").read()
@app.route("/")
def hello():
    return html
@app.route("/data", methods=["POST", "GET"])
def data():
    if request.method == "GET":
        return "The URL /data is accessed directly. Try going to '/form' to submit form"
    if request.method == "POST":
        text = request.form["Text"]
        w = request.form["Width"]
        h = request.form["Height"]
        //process your code
    return //value of your code
Yanky
  • 11
  • 2