I want to use ajax to restart servers from a flask web app.
My solution
Iterate over a folder of .bat files that restart servers, and send the name of the file to a flask function.
In my html, I'm using jinja2 to loop over files, and then create links to the ajax call.
Problem
something is wrong with my ajax, because it doesn't do anything
here is the view.
#app.route('/restartajax/<computer>')
def restartajax(computer):
print 'code'
def runJob(computer):
try:
subprocess.call(r"\\covenas\decisionsupport\meinzer\production\bat\restart\%s" % computer)
except Exception,e:
print 'there was an exception', e
thr = Thread(target = runJob, args = [computer])
thr.start()
return jsonify(result=computer)
html
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="{{
url_for('static', filename='jquery.js') }}">\x3C/script>')</script>
<script type=text/javascript>
$SCRIPT_ROOT = {{ request.script_root|tojson|safe }};
</script>
<div class="col-md-12">
<div class="well well-lg">
<div class="container">
<h1>Restart a Computer or Server</h1>
<p>Clickit.</p>
{% for item in restartFiles %}
{% if 'Backup' not in item and 'dummy' not in item %}
<div class="col-md-4">
<script type=text/javascript>
$(function() {
$('a#calculate').bind('click', function() {
$.getJSON($SCRIPT_ROOT + '/restartajax/'+item, {
}, function(data) {
$("#result").text(data.result);
});
return false;
});
});
</script>
<h4>{{item}}</h4>
<span id=result>?</span>
<p><a href=# id=calculate>restart {{item}}</a>
</div>
{%endif%} {%endfor%}
Modifications
I modified based on the answer, and it works!
{% for item in restartFiles %}
<div class="col-md-4">
<script type=text/javascript>
$(function() {
$('a.calculate').bind('click', function() {
var item = $(this).attr('id');
$.getJSON($SCRIPT_ROOT + '/restartajax/'+item, {
}, function(data) {
$("#result").text(data.result);
});
return false;
});
});
</script>
<h4>{{item}}</h4>
<span class="result">?</span>
<p>restart {{ item }}
</div>
{%endif%} {%endfor%}
the view
#app.route('/restartajax/<computer>')
def restartajax(computer):
def runJob(computer):
try:
subprocess.call(r"\\covenas\decisionsupport\meinzer\production\bat\restart\%s" % computer)
except Exception,e:
print 'there was an exception', e
thr = Thread(target = runJob, args = [computer])
thr.start()
return jsonify(result=computer)
item doesn't seem to be defined inside your calculate function, and you haven't given it any way to work it out. You need to send something to the function that identifies which item you have clicked on.
Also, since you have multiple items, you need to choose a different ID for each link: it's invalid in HTML to have more than one ID with the same value. Use a class instead of an ID to bind the jQuery listener.
restart {{item}}
$('a.calculate').bind('click', function() {
var item = $(this).attr('id');
$.getJSON ...
Related
I am trying to write a small web application using Flask. But I have a question while creating selection list. For example, there are 2 selection lists in the web. The first one is "keyID" and second one is "fieldName". When user clicked an item in selection list "keyID" then a corresponding selection list "fieldName" appears.
Here's the HTML:
<div class="control">
<label for="keyid">KeyID of parking spots:</label><br>
<select name ="keyidList" id="keyid_list" style="width: 400px">
{% for keyid in keyIDs %}
<option value ="{{keyid}}">{{keyid}}</option>
{% endfor %}
</select><br><br>
</div>
<div class="control">
<label for="fieldname">FieldName of parking spots:</label><br>
<select name ="fieldnameList" id="fieldname_list" style="width: 400px">
{% for fieldname in fieldnames %}
<option value ="{{fieldname}}">{{fieldname}}</option>
{% endfor %}
</select><br><br>
</div>
Javascript code in HTML file
<head>
<meta charset="utf-8">
<script>
$(function(){
var select_keyid = $('#keyid_list');
var selected_keyid = select_keyid.val();
select_keyid.on('change', function(){
$.ajax({
type: 'POST',
data: JSON.stringify({
'selected_keyid': selected_keyid,
}),
url: "{{ url_for('auth.get_fieldname_list') }}",
success: function(data) {
$("#fieldname").empty();
for (var i = 0; i < data.length; i++) {
$("#fieldname").append('<option value="' +fieldname+ '">' + fieldname + '</option>');
}
}
});
});
});
</script>
</head>
And here's the Python Flask code
#auth.route('/get_fieldname_list', methods=['POST'])
def get_fieldname_list():
req = request.json
keyid = req.get('selected_keyid')
fieldname = get_field_name_from_keyid(keyid)
return fieldname
I personally think that, the problem is with ajax code but I don't know why and how to fix it. Any advice will be really appreciated.
I am attempting to take what a user highlights in order to process it for a query of a database. While I seem to be able to successfully get what is being highlighted, it seems that passing that information through to the actual database query isn't happening. There aren't any error messages. I hope there is a typo somewhere and it is an easy fix, in any scenario an extra set of eyes from a more experienced person would be greatly appreciated. I am using Python Flask to develop a web app for personal use, here is the code
{% block content %}
<head>
<style>
div.sticky {
position: -webkit-sticky;
position: sticky;
top: 0;
float: right;
width: 30%;
}
</style>
</head>
<h2 style="text-align: center;">{{ name }}</h2>
<div class="sticky" id="sticky_display">
<button type="button" onclick ="getSelectedText()" style="background: darkblue; color: white;">Query Database</button>
<form name="testform">
<textarea id="selectedtext">
</textarea>
</form>
</div>
<div class="row">
<div class="col-xs-8 col-sm-8 col-md-8 col-lg-8" style="white-space: pre-line;" id="text_display">
{{ text }}
</div>
</div>
<script>
function getSelectedText() {
var selectedText = '';
if (window.getSelection) {
selectedText = window.getSelection();
}
// document.getSelection
else if (document.getSelection) {
selectedText = document.getSelection();
}
// document.selection
else if (document.selection) {
selectedText = document.selection.createRange().text;
} else return;
function(selectedText) {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function(){
if (this.readyState == 4 && this.status == 200) {
document.getElementById('selectedtext').value = this.responseText;
}
xhttp.open("POST", "/query_database', true);
xhttp.send(selectedText);
}
}
</script>
{% endblock %}
By default, POST will send
Content-Type: application/x-www-form-urlencoded
which requires that send a URL-encoded form. It appears that you're sending plain text, which would require adding
xhttp.setRequestHeader('Content-Type', 'text/plain');
before the .send()
I'm currently trying out some Jquery in combination with Flask. The problem which I'm facing is that if I want to do a request of a variable it gives me this Error "raise exceptions.BadRequestKeyError(key)".
Does anyone know how to fix this? I would like to enter a number in the input box and after pressing the "led on" button, I would like to print that value out on my terminal.
#app.route("/led/<int:state>", methods=['POST', 'GET'])
def led(state):
if state == 0:
print("es ist 0")
elif state == 1:
intervall = request.form['intervallMinuten']
print(intervall)
else:
return ('Unknown LED state', 400)
return ('', 204)
<div class="col-md-4">
<label>Intervall in <strong>Minuten</strong>:</label>
<input type="number" id="intervall" step="0.1" name='intervallMinuten'> </input>
<h3>LED</h3>
<button class="btn btn-default" type='button' id='led_on'>LED ON</button>
<button class="btn btn-default" type='button' id='led_off'>LED OFF</button>
</div>
<script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.12.0.min.js"><\/script>')</script>
<script>
$(document).ready(function() {
// Setup button click handlers.
$('#led_on').click(function() {
console.log('LED on!');
$.post('/led/1');
});
$('#led_off').click(function() {
console.log('LED off!');
$.post('/led/0');
});
});
</script>
You need to add 'intervallMinuten' in your post form, like this
<script src="https://code.jquery.com/jquery-1.12.0.min.js"></script>
<script>window.jQuery || document.write('<script src="js/vendor/jquery-1.12.0.min.js"><\/script>')</script>
<script>
$(document).ready(function() {
// Setup button click handlers.
$('#led_on').click(function() {
console.log('LED on!');
$.post('/led/1',{intervallMinuten: 2});
});
$('#led_off').click(function() {
console.log('LED off!');
$.post('/led/0', {intervallMinuten: 2});
});
});
</script>
So I was doing a django project by following a youtube video. And I got this error:
"Forbidden (403) CSRF verification failed. Request aborted."
everytime when I submit any data in my sign-up.html file.
Then I realize I did not configure ajax correctly. So I search online and saw the django documentation of ajax. I made some changes in my html code. still, it did not solve my problem.
I am still getting the same result. What is my mistake here. Did I made any mistake while configuring ajax?
"assets/js/django-ajax.js"
This is where i save the jquery file.
Its been a while since I am stuck in this problem.
Thank you for your time
My sign-up.html file:
{% load static %}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Instapic</title>
<link rel="stylesheet" href="{% static 'assets/bootstrap/css/bootstrap.min.css' %}">
<link rel="stylesheet" href="{% static 'assets/css/Login-Form-Clean.css' %}">
<link rel="stylesheet" href="{% static 'assets/css/styles.css' %}">
</head>
<body>
<div class="login-clean">
<form method="post">
{% csrf_token %}
<h2 class="sr-only">Login Form</h2>
<div class="illustration">
<div style="display: none" id="errors" class="well form-error-message"></div>
<img src="{% static 'assets/img/logo.jpg' %}">
</div>
<div class="form-group">
<input class="form-control" id="username" type="text" name="username" required="" placeholder="Username" maxlength="20" minlength="4">
</div>
<div class="form-group">
<input class="form-control" id="email" type="email" name="email" required="" placeholder="Email" maxlength="100" minlength="6">
</div>
<div class="form-group">
<input class="form-control" id="password" type="password" name="password" required="" placeholder="Password" maxlength="20" minlength="6">
</div>
<div class="form-group">
<button class="btn btn-primary btn-block" id="go" type="submit">Create Account</button>
</div>Already got an account? Login here ...</form>
</div>
<script src="{% static 'assets/js/jquery.min.js' %}"></script>
<script src="{% static 'assets/bootstrap/js/bootstrap.min.js' %}"></script>
<script src="{% static 'assets/js/django-ajax.js' %}"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#go').click(function() {
$.post("ajax-sign-up",
{
username: $("#username").val(),
email: $("#email").val(),
password: $("#password").val()
},
function(data, status){
if (JSON.parse(data).Status == 'Success') {
window.location = '/';
} else {
$('#errors').html("<span>" + JSON.parse(data).Message + "</span>")
$('#errors').css('display', 'block')
}
});
return false;
})
})
</script>
</body>
</html>
My ajax configureation:
// using jQuery
function getCookie(name) {
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
function sameOrigin(url) {
// test that a given url is a same-origin URL
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
Your click handler does not prevent the event from propagating. When your event handler has run the event will propagate and will eventually submit the form as a regular browser POST. You need to prevent this from happening
$('#go').click(function(event) {
event.stopPropagation();
I would suggest, add your csrf_token in every ajax.post for test, to be sure that generated token in cookies is correct.
Example:
$.ajax({
type: 'POST',
url: "",
data: {
username: $("#username").val(),
email: $("#email").val(),
password: $("#password").val(),
'csrfmiddlewaretoken': getCookie('csrftoken')
}
})
In your code. you defined method getCookie in JS, create variable csrf_token and implement this variable in ajaxSetup. Well, token is changing, but your script does not reload it.
If you want to use ajax.setup, put inside there the method getCookie, to be sure that ajax before send retakes correct token.
There are related questions here and here but they don't solve my problem.
Let's say I have a file testdata.csv like this:
A,B
1,3
2,4
and I want the user allow to upload the file and then - just for simplicity - display its content on the same page without affecting any other elements on this page. So my desired outcome would look like this:
How would I do this? I found a couple of approaches that use a form to load the file and send its (modified) content back (to e.g. download it) but I struggle to find a solution to pass the JSON response back to modify the page (here: add the table).
This is my entire code:
from flask import Flask, render_template, request, jsonify
import pandas as pd
import numpy as np
import json
# Initialize the Flask application
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/_get_table', methods=["POST", "GET"])
def get_table():
# how to catch the file here and send its content back?
# file = ????
# print(file)
df = pd.DataFrame({"A": [1, 2], "B": [3, 4]})
return jsonify(my_table=json.loads(df.to_json(orient="split"))["data"],
columns=[{"title": str(col)} for col in json.loads(df.to_json(orient="split"))["columns"]])
# if I use a form, I can use
# file = request.files['myfile']
# however, how do I then send the JSON response?
if __name__ == '__main__':
app.run(debug=True)
and my index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="header">
<h3 class="text-center text-muted">Some great stuff</h3>
</div>
<hr class="mb-4">
<div class="custom-file">
<input id="myfile" name="myfile" type="file" class="custom-file-input">
<label for="myfile" class="custom-file-label">
Choose file...
</label>
</div><br><br>
<button class="btn btn-primary" type="button" id="upload_document">Upload and process!</button>
<hr class="mb-4">
<table id="pretty_table" class="table table-striped"></table>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js" type="text/javascript"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
var table = null;
$('#upload_document').bind('click', function() {
$.getJSON('/_get_table', {
// what to pass here?
}, function(data) {
if (table !== null) {
table.destroy();
table = null;
$("#pretty_table").empty();
}
table = $("#pretty_table").DataTable({
data: data.my_table,
columns: data.columns
});
});
return false;
});
$('.custom-file-input').on('change', function() {
let fileName = $(this).val().split('\\').pop();
$(this).next('.custom-file-label').addClass("selected").html(fileName);
});
});
</script>
</body>
</html>
#charlietfl in the comments and this link got me on the right track. One can use FormData and then an .ajax call to achieve the desired outcome. So the important parts of above's link are (the complete files can be found below):
<form method="POST" enctype="multipart/form-data" id="fileUploadForm">
<div class="custom-file">
<input id="myfile" name="myfile" type="file" class="custom-file-input">
<label for="myfile" class="custom-file-label">
Choose file...
</label>
</div>
</form>
and
// Get form
var form = $('#fileUploadForm')[0];
// Create an FormData object
var data = new FormData(form);
and
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/_get_table",
data: data,
processData: false,
The processData: false, is important to prevent jQuery form transforming the data into a query string as explained in the link above.
On the flask site, we can then easily retrieve the file by doing:
file = request.files['myfile']
df = pd.read_csv(file)
which turns the .csv into a pandas dataframe. Clearly, there should be checks etc before doing this.
The entire HTML page index_formdata.html would look like this:
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<div class="header">
<h3 class="text-center text-muted">Some great stuff</h3>
</div>
<hr class="mb-4">
<form method="POST" enctype="multipart/form-data" id="fileUploadForm">
<div class="custom-file">
<input id="myfile" name="myfile" type="file" class="custom-file-input">
<label for="myfile" class="custom-file-label">
Choose file...
</label>
</div>
</form><br><br>
<button class="btn btn-primary" type="button" id="upload_document">Upload and process!</button>
<hr class="mb-4">
<table id="pretty_table" class="table table-striped"></table>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js" type="text/javascript"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script type="text/javascript">
$(document).ready(function () {
var table = null;
$("#upload_document").click(function (event) {
//stop submit the form, we will post it manually.
event.preventDefault();
// Get form
var form = $('#fileUploadForm')[0];
// Create an FormData object
var data = new FormData(form);
// disabled the submit button
$("#upload_document").prop("disabled", true);
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "/_get_table",
data: data,
processData: false,
contentType: false,
cache: false,
timeout: 600000,
success: function (data) {
if (table !== null) {
table.destroy();
table = null;
$("#pretty_table").empty();
}
table = $("#pretty_table").DataTable({
data: data.my_table,
columns: data.columns
});
$("#upload_document").prop("disabled", false);
},
error: function (e) {
alert(e.responseText);
console.log("ERROR : ", e);
$("#upload_document").prop("disabled", false);
}
});
});
$('.custom-file-input').on('change', function() {
let fileName = $(this).val().split('\\').pop();
$(this).next('.custom-file-label').addClass("selected").html(fileName);
});
});
</script>
</body>
</html>
the flask file as follows:
from flask import Flask, render_template, request, jsonify
import pandas as pd
import numpy as np
import json
# Initialize the Flask application
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index_formdata.html')
#app.route('/_get_table', methods=["POST", "GET"])
def get_table():
# catch file from the form; if you have several files, just make several requests (access by name)
file = request.files['myfile']
df = pd.read_csv(file)
return jsonify(my_table=json.loads(df.to_json(orient="split"))["data"],
columns=[{"title": str(col)} for col in json.loads(df.to_json(orient="split"))["columns"]])
if __name__ == '__main__':
app.run(debug=True)
and the testdata.csv file
A,B,C
1,3,123
2,4,456