Flask, AJAX, & Bootstrap Tables
This article shows you how to setup a Flask web app that loads a JSON object into an HTML table. It also re-creates the table by making an AJAX POST request to a Flask endpoint.
Quick version
For everyone that likes to see the results asap follow these steps to run the project locally.
- git pull https://github.com/jdougal84/Flask_AJAX_Table.git
- cd <project directory>
- pip install flask
- python app.py
Step by step
If you don’t want to download the repo you can manually create the folders/files in the project structure below and copy/paste the code.
Overview
When you run the Flask web app and go to http://127.0.0.1:5000/ in your browser the @app.route(‘/’) renders index.html. We pass the first JSON object ‘data_set_1’ to the Jinja2 variable ‘data’. In index.html we use Jinja2 expressions to create a for loop and iterate over the JSON object to build the table.
Project structure

Python
app.py
from flask import Flask, render_template, jsonify, request
import pandas as pd
import json
import os
app = Flask(__name__)
app.config['JSON_SORT_KEYS'] = False
project_dir = os.path.dirname(os.path.abspath(__file__))
my_files = r'/static/data/'
file_dir = project_dir + my_files
@app.route('/')
def index():
json_file = file_dir + r'data_set_1.json'
with open(json_file) as f:
js_object = json.load(f)
df = pd.read_json(json.dumps(js_object))
return render_template('index.html', data=df)
@app.route('/get_data', methods=['POST'])
def get_data_function():
user = request.form['user']
if user == 'two':
json_file = file_dir + r'data_set_2.json'
with open(json_file) as f:
js_object = json.load(f)
return jsonify(js_object)
else:
json_file = file_dir + r'data_set_1.json'
with open(json_file) as f:
js_object = json.load(f)
return jsonify(js_object)
if __name__ == '__main__':
app.run(debug=True)HTML
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>AJAX Example</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css">
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.1.3/js/bootstrap.min.js"></script>
<script src="{{ url_for('static', filename='js/ajax_table_example.js') }}"></script>
</head>
<body>
<h2> [Example] </h2>
<div class="container">
<form enctype="multipart/form-data" action='download' method="POST">
<div class="form-row mb-3">
<div class="input-group col-sm-8">
<div class="input-group-prepend">
<button type="button" id="ajax_data_load" class="btn btn-secondary fixed-button-size">Run</button>
</div>
<select name="user" class="custom-select fixed-button-size">
<option value="one">Option..</option>
<option value="one">One</option>
<option value="two">Two</option>
</select>
</div>
</div>
</form>
<table id="jds-example" class="table">
<thead>
<tr>
{% for col in data.columns %}
<th scope="col"> {{ col }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for key, value in data.iterrows() %}
<tr>
{% for k in value %}
<td scope="row">{{ k }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>Styling
main.css
table {
table-layout: responsive-sm;
}
thead th {
background-color: #FFA500;
color: white;
}
td {
white-space: normal !important;
word-wrap: break-word;
}
.fixed-button-size {
width: 100px !important
}JSON
data_set_1.json
[{
"name": "John Doe",
"position": "Sales",
"salary": "$100,000",
"start_date": "2015",
"office": "New York",
"extn": "5421"
},
{
"name": "Larry Doe",
"position": "Trader",
"salary": "$100,000",
"start_date": "2018",
"office": "Tokyo",
"extn": "2154"
}]data_set_2.json
[{
"name": "Joe Doe",
"position": "Technology",
"salary": "$100,000",
"start_date": "2015",
"office": "Miami",
"extn": "4512"
},
{
"name": "Ashley Doe",
"position": "Fashion",
"salary": "$100,000",
"start_date": "2015",
"office": "Alaska",
"extn": "1245"
}]If there were no errors, you’ll see this in your browser:

AJAX
To update an element in the DOM we do an asynchronous call with AJAX to our flask endpoint @app.route(‘/get_data’, methods=[‘POST’]) to get a new JSON object. We then build a new HTML table with the same CSS styling. This gives our web app a modern day feel.
$(document).ready(function(){
$('#ajax_data_load').click(function(){
clicked = $(this).attr('name');
$.ajax({
url: '/get_data',
dataSrc: 'data',
type: 'POST',
dataType: 'json',
data: $('form').serialize(),
success: function(data){
console.log('Success Hit');
console.log(data);
$('#jds-example').html('');
var column_data = '';
column_data += '<tr>';
for (var key in data[0]){
column_data += '<th>' + key + '</th>'
};
column_data += '</tr>';
$('#jds-example').append(column_data),
$('th').css({'background-color':'#FFA500', 'color': 'white'});
var row_data = '';
for (var arr in data){
var obj = data[arr];
row_data += '<tr>';
for (var key in obj){
var value = obj[key];
row_data += '<td>' + value + '</td>';
};
row_data += '</tr>'
};
$('#jds-example').append(row_data);
},
error: function(data){
console.log('Error Hit');
console.log(data);
}
});
});
});If there are no errors you’ll see this in your browser:

You can also inspect the app in your browser and see the message ‘Success Hit’ we wrote to the console and the object loaded from our flask endpoint and :

