97

I am new to python and Flask. I have a Flask Web App with a button. When I click on the button I would like to execute a python method not a Javascript method. How can I do this?

I have seen examples with python where it redirects me to a new page using a form tag like this

<form action="/newPage" method="post">

but I don't want it to redirect me to a new page. I just want it to execute the python method. I am making this for a Raspberry Pi robot car. When I press the forward button, I want it to run the method to Turn wheels forward.

Button HTML Code (index.html)

<button name="forwardBtn" onclick="move_forward()">Forward</button>

simple app.py Code - move_forward() method located here

#### App.py code

from flask import Flask, render_template, Response, request, redirect, url_for
app = Flask(__name__)

@app.route("/")
def index():
    return render_template('index.html');

def move_forward():
    #Moving forward code
    print("Moving Forward...")

I have seen similar questions to mine on Stackoverflow, but they don't seem to answer my question or I am unable to understand the answer. If someone could please provide me a simple way to call a Python method on button click event, it would be greatly appreciated.

Other Questions that I have looked at:

--Python Flask calling functions using buttons

--Calling a python function with a button

--Flask Button run Python without refreshing page?

Community
  • 1
  • 1
Amaan
  • 1,473
  • 2
  • 12
  • 11
  • I hope you already solved the problem (according to the fact that you've deleted [your question](https://stackoverflow.com/questions/47361134)). My point was that your input shape is `(120, 320, 3)`, but you're feeding the model with arrays of shape `n x 1` (or whatever your `batchSize` is). –  Nov 18 '17 at 00:40

6 Answers6

68

You can simply do this with help of AJAX... Here is a example which calls a python function which prints hello without redirecting or refreshing the page.

In app.py put below code segment.

#rendering the HTML page which has the button
@app.route('/json')
def json():
    return render_template('json.html')

#background process happening without any refreshing
@app.route('/background_process_test')
def background_process_test():
    print ("Hello")
    return ("nothing")

And your json.html page should look like below.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script type=text/javascript>
        $(function() {
          $('a#test').on('click', function(e) {
            e.preventDefault()
            $.getJSON('/background_process_test',
                function(data) {
              //do nothing
            });
            return false;
          });
        });
</script>


//button
<div class='container'>
    <h3>Test</h3>
        <form>
            <a href=# id=test><button class='btn btn-default'>Test</button></a>
        </form>

</div>

Here when you press the button Test simple in the console you can see "Hello" is displaying without any refreshing.

mplungjan
  • 169,008
  • 28
  • 173
  • 236
Gihan Gamage
  • 2,944
  • 19
  • 27
  • 2
    One problem with this solution is that `a` href parameters are overridden. Meaning that if you want, for example, to use that `a` tag to jump the user to a different location on the page, it will activate the python function but no longer function as a link. This can be solved with additional javascript but I am not sure if there is a flask or HTML based solution: https://stackoverflow.com/q/59342706/6924364 – Justapigeon Dec 15 '19 at 23:15
  • 7
    I have a very similar code to this one. What can I do if I want some data passed to the `background_process_test()` function from the button, through, say, a POST method? – mazunki Jan 08 '20 at 22:35
  • 2
    @mazunki if you want to pass paramters to background_process_test function, you could add onclick event to button and call function with it's parameter, this worked for me without adding ajax script – Ravi Bandoju Dec 01 '20 at 17:17
33

It sounds like you want to use this web application as a remote control for your robot, and a core issue is that you won't want a page reload every time you perform an action, in which case, the last link you posted answers your problem.

I think you may be misunderstanding a few things about Flask. For one, you can't nest multiple functions in a single route. You're not making a set of functions available for a particular route, you're defining the one specific thing the server will do when that route is called.

With that in mind, you would be able to solve your problem with a page reload by changing your app.py to look more like this:

from flask import Flask, render_template, Response, request, redirect, url_for
app = Flask(__name__)

@app.route("/")
def index():
    return render_template('index.html')

@app.route("/forward/", methods=['POST'])
def move_forward():
    #Moving forward code
    forward_message = "Moving Forward..."
    return render_template('index.html', forward_message=forward_message);

Then in your html, use this:

<form action="/forward/" method="post">
    <button name="forwardBtn" type="submit">Forward</button>
</form>

...To execute your moving forward code. And include this:

{{ forward_message }} 

... where you want the moving forward message to appear on your template.

This will cause your page to reload, which is inevitable without using AJAX and Javascript.

Logan Bertram
  • 1,874
  • 1
  • 16
  • 22
22

Easiest solution

<button type="button" onclick="window.location.href='{{ url_for( 'move_forward') }}';">Forward</button>
Vinit Bodhwani
  • 413
  • 1
  • 5
  • 16
19

index.html (index.html should be in templates folder)

<!doctype html>
<html>

<head>
    <title>The jQuery Example</title>

    <h2>jQuery-AJAX in FLASK. Execute function on button click</h2>  

    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"> </script>
    <script type=text/javascript> $(function() { $("#mybutton").click(function (event) { $.getJSON('/SomeFunction', { },
    function(data) { }); return false; }); }); </script> 
</head>

<body>        
        <input type = "button" id = "mybutton" value = "Click Here" />
</body>    

</html>

test.py

from flask import Flask, jsonify, render_template, request
app = Flask(__name__)


@app.route('/')
def index():
    return render_template('index.html')

@app.route('/SomeFunction')
def SomeFunction():
    print('In SomeFunction')
    return "Nothing"



if __name__ == '__main__':
   app.run()
user2371563
  • 364
  • 4
  • 14
1


PYTHON
you can create a generic route to execute everything you want in python:

@app.route('/<FUNCTION>')
def command(FUNCTION=None):
    exec(FUNCTION.replace("<br>", "\n"))
    return ""

JAVASCRIPT
now you create a javascript function to access the python function:

// pythonCommand can be any code in python
function ExecPythonCommand(pythonCommand){
    var request = new XMLHttpRequest()
    request.open("GET", "/" + pythonCommand, true)
    request.send()
}

ONCLICK
and finally call the javascript function in onclick and say what do you want execute in python script:

<button type="button" onclick="ExecPythonCommand('move_forward()')">i'm a button</button>

now its working! but we has some problems for example if try onclick="ExecPythonCommand('print('Hi!')')" because has much quotation marks, so you can create some javascript function to execute anything you want, this can be do like this:

// function created before
function ExecPythonCommand(pythonCommand){
    var request = new XMLHttpRequest()
    request.open("GET", "/" + pythonCommand, true)
    request.send()
}


// function to print Hi!
function PrintHi(){
    ExecPythonCommand("print('Hi!')") 
}


// function to print hour
function PrintHour(){
    ExecPythonCommand("import datetime as dt<br>print(dt.datetime.now().hour)")
    // in python script you was need import datatime as dt or pass all in the
    // function, for example ExecPythonCommand("import datetime as dt<br>print(dt.datetime.now().hour)")
    // and use <br> to break line (in python script i'm was converting to normal \n, using \n here has not working)
}


// function to do anything
function FunctionName(){
    ExecPythonCommand("some command") 
}

...

and call the function you want in onclick

basically exec() executes a string as a line of code

the order of process basically is onclick -> javascriptFunction -> pythonFunction

-1

Just put this at the end of your function

return '', 204

The HTTP 204 No Content success status response code indicates that a request has succeeded, but that the client doesn't need to navigate away from its current page. https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/204

Found it in this question: Python Flask Intentional Empty Response

raphaelDev
  • 21
  • 3