Rendering Flask template show the HTM page twice - python

I have a flask route rendering a template (method1_result.html) containing a dataframe table. Clicking the table row will send the cell value to another flask route to render a new template (method2_result.html). This last operation is showing a new result relevant to the Cell Clicked but the new html page (method1_result.html) is displaying the result twice.
main.py
#app.route("/method1",methods=['POST', 'GET'])
def method1():
'
'
return render_template('method1_result.html')
#app.route("/method2",methods=['POST', 'GET'])
def method2():
if request.method == 'POST':
# get info here to render page!
.
.
return render_template('method2_result.html',var1=var1)
method1.html
{% block content %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<br/>
<h3 align="center" style="color:blue" style="font-family:verdana">Method1 Result</h3>
<br/>
<div class="container-fluid">
<table id="table" class="table table-striped table-bordered" style="width: 100%">
<thread>
<tr>
{% for header in table[0].keys() %}
<th>{{header}}</th>
{% endfor %}
</tr>
</thread>
<tbody>
{% for row in table %}
<tr class='clickable-row'>
<td>{{row['Field1']}}</td>
<td>{{row['Field2']}}</td>
<td>{{row['Field3']}}</td>
<td>{{row['Field4']}}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
<script>
highlight_row();
function highlight_row(var1='') {
var table = document.getElementById('table');
var cells = table.getElementsByTagName('td');
for (var i = 0; i < cells.length; i++) {
// Take each cell
var cell = cells[i];
// do something on onclick event for cell
cell.onclick = function () {
// Get the row id where the cell exists
var rowId = this.parentNode.rowIndex;
var rowsNotSelected = table.getElementsByTagName('tr');
for (var row = 0; row < rowsNotSelected.length; row++) {
rowsNotSelected[row].style.backgroundColor = "";
rowsNotSelected[row].classList.remove('selected');
}
var rowSelected = table.getElementsByTagName('tr')[rowId];
rowSelected.style.backgroundColor = "yellow";
rowSelected.className += " selected";
msg = 'The Failure Message : ' + rowSelected.cells[6].innerHTML;
var var1 = rowSelected.cells[3].innerHTML;
$.ajax({
url:"/method2",
method:"POST",
data:{var1:var1},
success:function(data)
{
$('tbody').html(data);
$('tbody').append(data.htmlresponse);
},
})
}
}
}
</script>
{% endblock %}
method2.html
{% block content %}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<br/>
<h4 align="center" style="color:blue" style="font-family:verdana">Method2 result</h4><br/>
<br/>
<table id="table" class="table table-striped table-bordered table-hover" style="width: 100%">
<thread>
<tr>
{% for header in table1[0].keys() %}
<th>{{header}}</th>
{% endfor %}
</tr>
</thread>
<tbody>
{% for row in table1 %}
<tr>
<td>{{row['Start']}}</td>
<td>{{row['OperationID']}}</td>
<td style="color:red">{{row['Failure Message1']}}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
Not sure what Am doing wrong ?

In your code, you are doing an asynchronous call (ajax). An asynchronous call does not reload a page. This means that user is still on method1_result.html when the result (i.e. method2_result.html) comes in.
Your code also says to simply append the entire method2_result.html to method1_result.html page. In fact, you do it twice because you have
// First you append the entire response i.e. the entire method2 result
$('tbody').html(data);
// Then you try to do it a second time but just the 'htmlresponse' (not sure where you are getting this fro
$('tbody').append(data.htmlresponse);
If you want to replace the entire page (method1_result) with the entire contents of method2_result, then you don't need an Ajax call. Replace that ajax call with code that creates a form, creates an input element with the values of the data that you want to pass to the server, and then submits the form. Since this is not an ajax call, it will load a new page which is method2.html
var form = document.createElement("form");
form.method = "POST";
form.action = "/method2";
var elem = document.createElement("input");
elem.name= var1;
elem.value= var1;
form.appendChild(elem1);
document.body.appendChild(form);
form.submit();
If you don't want to replace the entire page (maybe you want to replace the body of the existing page with the new page), then you can't just do append which means to add to the existing content, unless you have first cleared the existing content. You have 2 options
Option 1
$('tbody').empty() // Remove the current contents
$('tbody').append(data); // Add the new contents
Option 2
$('tbody').html(data)

Related

Flask: How to display tables in SQLite onto Flask?

I have created a table in DB Browser SQLite with real data input. How do I link the SQLite with flask so that the table will be displayed in the html. I want the html part to be displayed exactly the same as DB Browser Sqlite.
This is my app.py
#app.route('/viewrec', methods=['POST', 'GET'])
def viewrec():
try:
if request.method == 'POST':
use = session['user'].get("name")
ema = session['user'].get("preferred_username")
depart = request.form['depart']
type = request.form['type']
uploadre = request.form['uploadre']
amt = request.form['amt']
description = request.form['description']
if request.form.get("price"):
price_checked = "Yes"
else:
price_checked = "No"
conn = sql.connect(db_path)
c = conn.cursor()
c.execute('SELECT * FROM SubmitClaim')
rows = c.fetchall()
return render_template("viewpastclaim.html", rows=rows)
except:
# for row in rows:
# print(row)
#
# conn.close()
return render_template('viewpastclaim.html')
This is my viewpastclaim.html
I tried to call the various variables from App.py and use them with rows['Name']
<form action="/viewrec" METHOD="POST" >
<!-- Generate all the claim content -->
<table style=" font-family: arial, sans-serif;
width: 60%;
border: 1px solid black;
margin-left:500px;
margin-top: 100px;
text-align: center;
padding:20px;">
<tr>
<th class="type">Name</th>
<th>Email</th>
<th>Department</th>
<th>ClaimType</th>
<th>UploadReceipt</th>
<th>ClaimAmount</th>
<th>checkbox</th>
<th>ClaimDescription</th>
</tr>
{% for rows in SubmitClaim %}
<tr>
<td>rows['Name']</td>
<td>rows['Email']</td>
<td>rows['Deparment']</td>
<td>rows['ClaimType']</td>
<td>rows['UploadReceipt']</td>
<td>rows['ClaimAmount']</td>
<td>rows['checkbox']</td>
<td>rows['ClaimDescription']</td>
</tr>
{% endfor %}
</table>
<!-- View all the claims -->
<button type="submit", class="viewall-button" name="save", value="save">View All</button>
</form>
If you are able to solve them, please drop a msg below. Thank you for your time.
You have to wrap your Python variables in {{ }} to show them in HTML format. You also have some errors in your code. You have to replace 'SubmitClaim' with rows since you passed that in your python function. So the correct code would be:
{% for row in rows %}
<tr>
{% for data in row %}
<td>{{ data }}</td>
{% endfor %}
</tr>
{% endfor %}
I think something like that should work. You are giving the info to the template inside of "rows" not inside of "SubmitClaim"
<tr>
<th class="type">Name</th>
<th>Email</th>
<th>Department</th>
<th>ClaimType</th>
<th>UploadReceipt</th>
<th>ClaimAmount</th>
<th>checkbox</th>
<th>ClaimDescription</th>
</tr>
{% for row in rows %}
<tr>
<td>row['Name']</td>
<td>row['Email']</td>
<td>row['Deparment']</td>
<td>row['ClaimType']</td>
<td>row['UploadReceipt']</td>
<td>row['ClaimAmount']</td>
<td>row['checkbox']</td>
<td>row['ClaimDescription']</td>
</tr>
{% endfor %}
If you still can't get it to work I suggest you use SQL-Alchemy to manage the database. That should make everything easier.

How can I add a Bar Chart to my Django based Database?

Dear community members,
I really hope that you will help me to add a Bar Graph to my Django project.
1. I have a Database with around 1000 items.
2. I need to be able visualise a 3 month sales for each item when needed.
Not sure what is a correct approach.
here is my models.py:
from django.db import models
from math import *
from decimal import *
class Itemslist(models.Model):
item_n = models.CharField(max_length=200)
sales_this_month = models.DecimalField(blank=True, null=True, max_digits=19,
decimal_places=0)
saleslm = models.DecimalField(blank=True, null=True, max_digits=19, decimal_places=0)
sales2m = models.DecimalField(blank=True, null=True, max_digits=19, decimal_places=0)
sales3m = models.DecimalField(blank=True, null=True, max_digits=19, decimal_places=0)
def __str__(self):
return self.item_n
here is my views.py file, that as an experiment I have created, using the last solution provided:
def charts(request):
charts = Itemslist.objects \
.values('saleslm') \
.annotate(lm=Count('saleslm')) \
.annotate(m2=Count('sales2m')) \
.annotate(3m3=Count('sales3m')) \
.order_by('saleslm')
return render(request, 'charts.html', {'charts': charts})
As you can see, this is not a solution I need, I was just trying to come up with at least something , and eaven that has shown me the graph with the same values.
here is my hmtl code:
{% extends 'base.html' %}
{% block js %}
{% if user.is_authenticated %}
{% load loads_extra %}
{% load static %}
<br>
<p>Logged in user: {{ user.username }}</p>
<br>
<html>
<head>
<meta charset="utf-8">
<title>Django Highcharts Example</title>
</head>
<body>
<div id="container"></div>
{
<script src="https://code.highcharts.com/highcharts.src.js"></script>
<script>
Highcharts.chart('container', {
chart: {
type: 'column'
},
title: {
text: 'Sales previous 3 months'
},
xAxis: {
categories: ['sales']
},
series: [{
name: '3mBack',
data: [ {% for entry in charts %}{{ entry.m3 }}{% endfor %} ]
}, {
name: '2mBack',
data: [ {% for entry in charts %}{{ entry.m2 }}{% endfor %} ]
}, {
name: 'Lmonth',
data: [ {% for entry in charts %}{{ entry.lm }}{% endfor %} ]
}, ]
});
</script>
</body>
</html>
{% endif %}
{% endblock %}
<!-- charting tutorial to follow : https://simpleisbetterthancomplex.com/tutorial/2018/04/03/how-to-integrate-highcharts-js-with-django.html -->
I have to create a request button for charts and then chart has to be generated with a right parameters.
Have looked at this question:
Displaying multiple bar graph in django
Also have searched through this solution
https://code.djangoproject.com/wiki/Charts
And looked at this article
https://simpleisbetterthancomplex.com/tutorial/2018/04/03/how-to-integrate-highcharts-js-with-django.html
The last article was the clearest one, and you can see, that I have just copy pasted the solution from there, with small changes.
here is a script that I have placed in my base.html file:
<script src="https://code.highcharts.com/highcharts.src.js"></script>
and that's the chart that I have finally got displayed:
But still can’t find how to deal with it in my situation.
All this solutions, as far as I can see, are showing how to implement charting to one array, or to sum or self generated array. But I want to be able to chose, when to show a graph and for which Item.
the button is placed on this html file:
{% extends 'base.html' %}
{% block js %}
{% if user.is_authenticated %}
{% load loads_extra %}
{% load static %}
<br>
<p>Logged in user: {{ user.username }}</p>
<br>
<body>
<table id="example" class="table table-striped table-bordered dt-responsive nowrap" style="width:100%">
<thead>
<tr>
<th>SUP:</th>
<th>Item N.:</th>
<th>SKU</th>
<th>Description</th>
<th>3mBack</th>
<th>2mBack</th>
<th>Lmonth</th>
<th>CMonth</th>
<th>Nmonth</th>
<th>N2Month</th>
<th>N3month</th>
<th></th>
</tr>
</thead>
<tbody>
{% for records in sorted %}
<tr>
<td>{{ records.sup }}</td>
<td>{{ records.item_n }}</td>
<td>{{ records.sku }}</td>
<td>{{ records.description }}</td>
<td>{{ records.sales3m }}</td>
<td>{{ records.sales2m }}</td>
<td>{{ records.saleslm }}</td>
<td>{{ records.sales_this_month }}</td>
<td>{{ records.m1predicted }}</td>
<td>{{ records.m2predicted }}</td>
<td>{{ records.m3predicted }}</td>
<td>
Edit
</td>
</tr>
{% endfor %}
</tbody>
</table>
<script>
$(document).ready(function() {
var table = $('#example').DataTable( {
fixedColumns: true,
lengthChange: true,
buttons: [ 'copy', 'excel', 'csv', 'pdf', 'colvis' ]
} );
table.buttons().container()
.appendTo( '#example_wrapper .col-md-6:eq(0)' );
} );
</script>
</body>
</html>
{% endif %}
<div></div>
{% endblock js %}
This is my first question in this community, so if something is not clear, please help me to correct it in a right way.
waiting for any helpful answers!!!
Good News community.
I have been offered a very good solution, and now my question is completely sorted.
At least for my needs, this is a perfect solution.
instead of highcharts, I have been offered to use d3js.org, which is absolutely fine for me.
The logic behind a code is that you request data from the values displayed, hopefully it will be clear, when you will go through the code with comments.
as it's a django project, here's the heading of my html file:
{% extends 'base.html' %}
{% block js %}
{% if user.is_authenticated %}
{% load loads_extra %}
{% load static %}
<br>
<p>Logged in user: {{ user.username }}</p>
<br>
here is a part of my html code that displays table/value:
<table id="example" class="table table-striped table-bordered dt-responsive nowrap" style="width:100%">
<thead>
<tr>
<th>SUP:</th>
<th>Item N.:</th>
<th>SKU</th>
<th>Description</th>
<th>6mBack</th>
<th>5mBack</th>
<th>4mBack</th>
<th>3mBack</th>
<th>2mBack</th>
<th>Lmonth</th>
<th>CMonth</th>
<th>Nmonth</th>
<th>N2Month</th>
<th>N3month</th>
<th>AVGrowth</th>
<th></th>
<!-- This is header for new button to draw the Bar Charts -->
<th></th>
</tr>
</thead>
<tbody>
{% for records in sorted %}
<tr>
<td>{{ records.sup }}</td>
<td>{{ records.item_n }}</td>
<td>{{ records.sku }}</td>
<td>{{ records.description }}</td>
<td>{{ records.sales6m }}</td>
<td>{{ records.sales5m }}</td>
<td>{{ records.sales4m }}</td>
<td>{{ records.sales3m }}</td>
<td>{{ records.sales2m }}</td>
<td>{{ records.saleslm }}</td>
<td>{{ records.sales_this_month }}</td>
<td>{{ records.m1predicted }}</td>
<td>{{ records.m2predicted }}</td>
<td>{{ records.m3predicted }}</td>
<td>{{ records.avgrowths }}</td>
<td>
Edit
</td>
<!-- Add new button for drawing Bar Charts -->
<td>
<button class="btn btn-secondary" onclick="draw_chart(this)" data-toggle="modal" data-target="#myModal">Chart</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
please read comments to understand what is what.
and here is the rest of html, that is generating a chart on a topup window,by pressing a button in front of an array that has to be visualised:
<!-- Modal which Bar Chart will be placed -->
<div id="myModal" class="modal fade" role="dialog">
<div class="modal-dialog" style="max-width: 900px !important">
<!-- Modal content-->
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal">×</button>
</div>
<div class="modal-body">
<!-- <svg> element which will contains the Bar Chart -->
<svg width="1000" height="500"></svg>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
<!-- Insert D3.js Library -->
<script src="https://d3js.org/d3.v5.min.js"></script>
<script>
$(document).ready(function() {
var table = $('#example').DataTable( {
fixedColumns: true,
lengthChange: true,
buttons: [ 'copy', 'excel', 'csv', 'pdf', 'colvis' ]
} );
table.buttons().container()
.appendTo( '#example_wrapper .col-md-6:eq(0)' );
} );
// Main functions for Drawing Bar chart using D3.js
function draw_chart(item){
// `item` is the current clicked button element
// `row_ele` is the parent <tr> element of the current clicked button element
row_ele = item.closest('tr');
// Get the value from the <td> element using nth-child()
val_6mBack = row_ele.querySelector("td:nth-child(5)");
val_5mBack = row_ele.querySelector("td:nth-child(6)");
val_4mBack = row_ele.querySelector("td:nth-child(7)");
val_3mBack = row_ele.querySelector("td:nth-child(8)");
val_2mBack = row_ele.querySelector("td:nth-child(9)");
val_Lmonth = row_ele.querySelector("td:nth-child(10)");
val_CMonth = row_ele.querySelector("td:nth-child(11)");
val_Nmonth = row_ele.querySelector("td:nth-child(12)");
val_N2Month = row_ele.querySelector("td:nth-child(13)");
val_N3month = row_ele.querySelector("td:nth-child(14)");
// `data` is variable which store the data for Bar Charts
data = []
// Pushing data as key/value type objects into the `data` variable
data.push({'label':'6mBack', 'value': val_6mBack.innerHTML})
data.push({'label':'5mBack', 'value': val_5mBack.innerHTML})
data.push({'label':'4mBack', 'value': val_4mBack.innerHTML})
data.push({'label':'3mBack', 'value': val_3mBack.innerHTML})
data.push({'label':'2mBack', 'value': val_2mBack.innerHTML})
data.push({'label':'Lmonth', 'value': val_Lmonth.innerHTML})
data.push({'label':'CMonth', 'value': val_CMonth.innerHTML})
data.push({'label':'Nmonth', 'value': val_Nmonth.innerHTML})
data.push({'label':'N2Month', 'value': val_N2Month.innerHTML})
data.push({'label':'N3month', 'value': val_N3month.innerHTML})
// Set <svg> element's width and height
var svg = d3.select("svg"),
margin = 200,
width = svg.attr("width") - margin,
height = svg.attr("height") - margin
// Remove the old contents of the <svg> element
svg.selectAll('*').remove()
// Initialize X-axis and Y-axis for Bar Chart
var xScale = d3.scaleBand().range([0, width]).padding(0.4),
yScale = d3.scaleLinear().range([height, 0]);
// Set all group which is placed in the <svg>element
// transform to (50,100) on <svg> area , margint in svg has been changed to 300 and instead 50/100, changed to 100/300, but then back.
var g = svg.append("g")
.attr("transform", "translate(" + 50 + "," + 100 + ")");
xScale.domain(data.map(function(d) { return d.label; }));
// If all values of data will be zero, we will fix the range of the Y-axis
if(d3.max(data, function(d) { return d.value; }) == 0){
yScale.domain([0, 10]);
}else{
// If all is not zero, we will set Y-axis from 0 to maximum value.
yScale.domain([0, d3.max(data, function(d) { return Number(d.value); })]);
}
// Set X- axis
g.append("g")
.attr("transform", "translate(0," + height + ")")
.call(d3.axisBottom(xScale));
// Set Y-axis using ticket
g.append("g")
.call(d3.axisLeft(yScale).tickFormat(function(d){
return d;
}).ticks(10));
console.log(data)
// Draw Bar Chart using <rect> element by data which is stored in the `data` variable
g.selectAll(".bar")
.data(data)
.enter().append("rect")
.attr("class", "bar")
.attr("x", function(d) { return xScale(d.label); })
.attr("y", function(d) { return yScale(d.value); })
.attr("width", xScale.bandwidth())
.attr("height", function(d) { return height - yScale(d.value); })
.style('fill','#899da6');
}
</script>
</body>
{% endif %}
{% endblock js %}
so finally here is how my html looks like live:
and here is a graph, that I get by pressing chart button:
in order to help community, please ask questions, and please add/correct if there is a better way.
Thank you very much for your help and attention!!!
views.py
You have an error on annotate(3m3 its cannot start with 3 here. You also have same function name and variable name def charts and charts inside. Python might be smart enough to figure it out but try to avoid doing this. I am also against naming variables saleslm and sales2m be explicit here.
def charts(request):
return render(request, 'charts.html')
def charts_ajax(request):
charts_data = Itemslist.objects \
.values('saleslm') \
.annotate(lm=Count('saleslm')) \
.annotate(m2=Count('sales2m')) \
.annotate(m3=Count('sales3m')) \
.order_by('saleslm')
return JsonResponse({'charts': list(charts_data)})
url.py
path('charts/', views.charts, name='charts_home'),
path('charts_ajax/', views.charts_ajax, name='render_charts_ajax')
html
You have multiple issues in your html file.
</html>
{% endif %}
<div></div>
{% endblock js %}
You have div after the html has ended. You should not have anything after html ends.
Few other organizational issues here. I usually would have a block content and then block js while you have everything inside block js. I would clean those. Now that you added datables also. You can add buttons as mentioned here. https://datatables.net/extensions/buttons/examples/initialisation/custom.html
but if i were you i would try to make it work with simple table and move on to datables.
<html>
<head>
<meta charset="utf-8">
<title>Django Highcharts Example</title>
</head>
<body>
<div id="container">
</div>
<button id="render_chart" type="button">Render Chart</button>
<script
src="https://code.jquery.com/jquery-3.4.1.min.js"
integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
crossorigin="anonymous"></script>
<script src="https://code.highcharts.com/highcharts.src.js"></script>
<script>
$(document).ready(function(){
$('#render_chart').on('click', function(e){
$.ajax({
url: "{% url 'render_charts_ajax'%}",
type: "GET",
dataType: "json",
success: function (data) {
console.log(data.charts[0].saleslm)
Highcharts.chart('container',{
chart:{
type:'bar'
},
title:{
text:"Sales Last Month"
},
series:[{
name:"Sales LM",
data:[parseInt(data.charts[0].saleslm)]
}]
})
}
})
})
});
</script>
</body>
</html>
Your json might need some processing before the chart comes out right.

Create a dropdown list for an existing column in html jinja

I have a dataframe created in flask. The df has 3 columns: "Account Description", "Amount", and "Mapping". The column "Mapping" takes 3 values: "Cash", "Debt", and "Equity"
The dataframe is sent to html jinja using:
return render_template('file.html', data=df,column_names=data.columns.values, row_names=list(data.values.tolist(), link_column="Mapping"))
What I need to do now is to create a dropdown list for every cell in the 'Mapping' column, with the default option value for each dropdown box being the existing value of the cell. Please look at my image link to get an idea. The pre-populated in those blue boxes should be the value of the cell instead of "select an option"
https://drive.google.com/file/d/1sadDR0x8pJRzeJRS6pSvfDaNmKyoJ31G/view?usp=sharing
Here's the html code i'm trying but not working:
<div>
<table id="Mapped table">
<h2>Mapped data</h2>
<tr>
{% for col in column_names %}
<th>{{col}}</th>
{% endfor %}
</tr>
{% for row in row_names %}
<tr>
{% for col_, row_ in zip(column_names, row) %}
{% if col_ == link_column %}
<td>
<select class="dropbtn">
<option value="none" selected disabled hidden>
#Select existing option of the column cell
</option>
<option value="1">Cash</option>
<option value="2">DebtAccrual</option>
<option value="3">Equity</option>
</select>
</div>
Button onclick event:
<script>
var a = document.getElementById("dropbtn");
var old = a.options[a.selectedIndex].text;
</script>
<div class="wrapper">
<button class="button" id="myBtn">Confirm mapping</button>
<script>
$('#myBtn').on('click', function(a) {
var drpdbJson = {};
// for each row containing a select....
$('#Mapped\\ table tr:gt(0):has(select)').each(function(idx, old_ele) {
// get the selected value
var old_drpdwnKey = $(old_ele).find('.dropbtn option:selected').text();
// get the second column text
var old_drpdwnValue = $(old_ele).find('td:eq(1)').text();
// add to the json result
if (drpdbJson[old_drpdwnKey] == undefined) {
drpdbJson[old_drpdwnKey] = old_drpdwnValue;
} else {
drpdbJson[old_drpdwnKey] = (typeof drpdbJson[old_drpdwnKey] === 'string') ?
[drpdbJson[old_drpdwnKey], old_drpdwnValue] : [...drpdbJson[old_drpdwnKey], old_drpdwnValue];
}
})
// print the json obj
console.log(JSON.stringify(drpdbJson))
$.post("http://localhost:5000/bs_mapped",JSON.stringify(drpdbJson))
})
</script>
</div>
I apologize if my code is not entirely reproducible. I would like to just have some general idea of how to accomplish this. Thank you very much.
As the dropdown has fixed values, we can pass the choice list from Flask to HTML template. And then if values are matched, we can add selected attribute to the option tag.
I have used to_dict('records') to pass each row as a dictionary where key is the column name and value is the data in the cell.
app.py:
from flask import Flask, render_template, url_for, request
import pandas as pd
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
account = pd.Series(["Petty cash", "Lucky Money", "RBC USD"])
amount = pd.Series([-2.59, 1111111, 66170.97])
mapping = pd.Series(["Debt", "Equity", "Cash"])
choices = (("Cash", "Cash"), ("Debt", "DebtAccrual"), ("Equity", "Equity"))
data = pd.DataFrame({
"Account Description":account,
"Amount":amount,
"Mapping":mapping
})
return render_template('index.html',
column_names=data.columns.values,
rows=data.to_dict('records'),
link_column="Mapping",
choices = choices
)
index.html:
<html>
<head>
<title>Dataframe in Flask template</title>
</head>
<body>
<div>
<h2>Mapped data</h2>
<table id="Mapped table" border="1">
<tr>
{% for col in column_names %}
<th>{{col}}</th>
{% endfor %}
</tr>
{% for row in rows %}
<tr>
{% for key, val in row.items() %}
{% if key == link_column %}
<td>
<select class="dropbtn">
{% for choice in choices %}
<option value={{ choice[0] }}
{% if choice[0] == val %} selected {% endif %}>
{{ choice[1] }}
</option>
{% endfor %}
</select>
</td>
{% else %}
<td>
{{ val }}
</td>
{% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
</body>
</html>
Screenshot:
Default option value for each dropdown box being the existing value of the cell:

Send table data from template to view.py in django

I am passing a list i.e data_code from view.py to a html file and from there i am printing the data of the table using for loop through the list. There is a editable column in the table <input> and i want to get those data after filled by user on my view.py. so anybody any idea how to do that??
I want to get all {{x.2}} in view.py. It is printing some default value but i want it again after it is being by user.
Here is the code:
<table class="table table-bordered datatable">
<thead class="table-head">
<tr>
<th>No</th>
<th>Code Point</th>
<th>Reference</th>
<th>Character</th>
<th>Text</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{% for x in data_code %}
<tr class="table-row">
<td>{{ forloop.counter }}</td>
<td><label>{{ x.0 }}</label></td>
<td><input id="codepoint_input" type="text" value={{x.2}} size=3 title="Text"></td>
<td><label> {{x.3}}</label></td>
<td>{{x.4}}</td>
</tr>
{% endfor %}
</tbody>
</table>
Edit:
Use dictionary type so that you can give each input box a unique name through the key, and use the corresponding value in value parm.
In view, you can use a for loop to go through the whole dictionary, and use the key to get the values from the template.
In your Template:
<form name = "yourForm" method="GET" action="/" class = "main">
{% for key, value in json.data_code%}
<td>
<input name = "{{ key }}" id="codepoint_input" type="text" value={{ value }} size=3 title="Text">
<input type="submit" id = "amountbtn" style="visibility:hidden;" >
</td>
{% endfor %}
</form>
In your views:
key1 = request.GET.get('key1')
....
The first task is get those entered values using jquery simply...
$(#codepoint_input).keypress(function(e) {
if(e.which == 13) {
// your custom code here.
var tablestring = $("#tableForm").serialize();
$.post( "/backend", tablestring );
}
});
Finally you can get the values in your view function...
def backend(request):
print(request.POST)

HTML override table element to show nothing

I am rendering a HTML table through Django. In this table, some of the cells or columns contain "0"'s as produced by my python code.
Is there any way in HTML to override that cell or column and for it to show instead a blank in the table cell rather than a 0?
I am using jQuery as well, if that helps.
<tr><td> Value</td>
{% for num in list %}
<td> <b>{{num}}</b>
{% endfor %}</td>
</tr>
Output is a list which contains 3 zero's...out of which I want two blanked out.
Lets say if I have something being returned that is
0
10
0
20
0
But want
""
10
""
20
0
$(".dem").each(function() {
for ( var i = 0; i<2; i++)
{
if ($(this).html() == "0") {
$(this).html(" ");
}
i = i+1
}
});
I did that ^....however it turned all 3 zeros blank...why?
Thanks!
See the last edit for my final answer. I'm leaving the rest in to show how important it is to ask a good question, and to show what was tried, what the input looked like and what the expected output should have been. That would have saved a lot of time.
Using jQuery, you can iterate over each table cell, check the value and change what it outputs. I prefer this over changing the actual data. It's better to leave your data intact and only change the way it is displayed here.
$("#test td").each(function() {
if ($(this).html() == "0") {
$(this).html("");
}
});
You can see it in action here.
Update:
If only some <td>s should be changed, I recommend using a class for those.
$(".noZeroAllowed").each(function() {
if ($(this).html() == "0") {
$(this).html("");
}
});
It works with HTML like this:
<table id="test">
<tr>
<td class="noZeroAllowed">10</td>
<td class="noZeroAllowed">5</td>
<td>0</td>
<td>1</td>
</tr>
<tr>
<td class="noZeroAllowed">11</td>
<td class="noZeroAllowed">0</td>
<td>9</td>
<td>7</td>
</tr>
</table>
Also see the updated fiddle.
Update 2:
If the data is not atomic and the cells have multiple values in them, like this:
<table id="test">
<tr>
<td class="noZeroAllowed">10 0 foobar 0</td>
<td class="noZeroAllowed">5</td>
<td>0, 0, 0</td>
<td>1</td>
</tr>
</table>
Then you need to change the Javascript to use a regular expression instead. The \b means a word boundary. It will not work with decimals like 0.5 though.
$(".noZeroAllowed").each(function() {
var newStr = $(this).html().replace(/\b0\b/g, "");
$(this).html(newStr);
});
See the updated fiddle.
Update 3:
This will turn all the zeros inside of <b> tags in the relevant class <td>s into empty strings, but leave the last zero intact.
$(".noZeroAllowed").each(function() {
var zeros = new Array;
var b = $(this).find("b");
for (var i = 0; i < b.length; i++) {
$(b[i])
if ($(b[i]).html() == "0") {
zeros.push(b[i]);
}
}
for (var i = 0; i < zeros.length - 1; i++) {
$(zeros[i]).html("");
}
});
See it here.
If the zeros are the only thing that evaluates false, you can use the default template filter:
{{ value|default:" " }}
You may need to use the actual unicode character
{{ value|default:"\u00A0" }}
In response to your edit:
<tr><td> Value</td>
{% for num in list %}
<td> <b>{{ num|default:"\u00A0" }}</b>
{% endfor %}</td>
</tr>
For changing only the first row:
<tr><td> Value</td>
{% for num in list %}
<td> <b>{% if forloop.first %} {% else %}{{ num }}{% endfor %}</b>
{% endfor %}</td>
</tr>
For more on the forloop variables, check here.
You could use Django's templates (see documentation):
{% if val != 0 %}{{ val }}{% endif %}
Alternatively, if you want something neater, you could use a Django filter in a template:
{{ val | default: "" }}
... Colin beat me to that one. ;) See the documentation for the 'default' filter.
EDIT: In answer to your comment, you'd do it like this:
{% for num in list %}
<td><b>{{num | default: ""}}</b></td>
{% endfor %}
Note that you had your </td> outside the for loop, whereas it needs to be inside.

Categories

Resources