Load CSV file in Django view and turn into HTML table - python

I have this view code
def datatable(request, file):
csv_fp = open(f'data/{file}.csv', 'r')
reader = csv.DictReader(csv_fp)
headers = [col for col in reader.fieldnames]
out = [row for row in reader]
return render(request, 'datatable.html', {'data' : out, 'headers' : headers})
and here's my template
<table id="table" class="display" style="width: 100%;">
<thead>
<tr>
{% for header in headers%}
<th>{{ header }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr>
{% for row in out%}
<td>{{row}}</td>
{% endfor %}
</tr>
</tbody>
</table>
I'm trying to turn this CSV into a table in my Django template. The headers are done correctly, but the rows are off. Is there a better way to read the rows so it'll go into tbody easier?

Seems that your problem is {% for row in out %}, you are passing {'data' : out}
Try:
<table id="table" class="display" style="width: 100%;">
<thead>
<tr>
{% for header in headers %}
<th>{{ header }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
<tr>
{% for row in data %}
<td>{{ row }}</td>
{% endfor %}
</tr>
</tbody>
</table>

Related

Python list of dict to html table (Flask)

I have a list of dict:
data = [{'2479': {'2022-09-04 to 2022-09-10': 28, '2022-08-28 to 2022-09-03': 27},
'ADMINISTRATION': {'2022-09-04 to 2022-09-10': 8},
'1361': {'2022-09-04 to 2022-09-10': 4, '2022-08-28 to 2022-09-03': 5},
'PERSONAL TIME OFF': {'2022-08-28 to 2022-09-03': 8}}]
# '2479' is the project number
# '2022-09-04 to 2022-09-10' is the date range
# 28 is the total number of hours used for the project for that week
I'm trying to convert it to an html table like this:
So far, this is what I have:
Here's my code:
{% macro render_table_header(label) %}
{% for record in content["weeklyUserReport"] %}
{% for project in record %}
{% for week in record[project] %}
<th class="rotate-45 week1">
<div><span class="date">{{week}}</span></div>
</th>
{% endfor %}
{% endfor %}
{% endfor %}
{% endmacro %}
<table
class="table table-header-rotated table-striped-column hours-container"
id="grid"
>
<thead>
<tr>
<th class="row-header"></th>
{{ render_table_header() }}
</tr>
</thead>
<tbody>
{% for record in content["weeklyUserReport"] %}
{% for project in record %}
{% for week in record[project] %}
<tr>
{% if record[project] == project %}
<td class="project-name"></td>
{% else %}
<td class="project-name">{{ project }}</td>
{% endif %}
<td class="week1">{{ record[project][week] }}</td>
</tr>
{% endfor %}
{% endfor %}
{% endfor %}
</tbody>
</table>
I'd like duplicated projects to be removed and for the hours to line in to their corresponding rows. I have <td class="week2">, <td class="week3">, and <td class="week4"> for the other hours but I'm struggling to find a way to do that.
Any suggestions would be greatly appreciated! Thank you.
I think you were confused about how to properly do loops through the list of dictionaries on the jinja template. I can give a "replica" of what you have done. Try to do something like this on your HTML:
<body>
<table class="table table-header-rotated table-striped-column hours-container" id="grid" style="border: 1px solid black">
<thead>
<tr>
<th style="border: 1px solid black">project name</th>
{% for d in date %}
<th class="row-header" style="border: 1px solid black">{{d}}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for record in data %}
{% for project_key, project_value in record.items() %}
<tr>
<td>{{ project_key }}</td>
{% for value in project_value.values() %}
<td class="week1" style="border: 1px solid black">{{ value }}</td>
{% endfor %}
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
</body>
Here is my controller:
#app.route("/")
def index():
data = [{'2479': {'2022-09-04 to 2022-09-10': 28, '2022-08-28 to 2022-09-03': 27},
'ADMINISTRATION': {'2022-09-04 to 2022-09-10': 8},
'1361': {'2022-09-04 to 2022-09-10': 4, '2022-08-28 to 2022-09-03': 5},
'PERSONAL TIME OFF': {'2022-08-28 to 2022-09-03': 8
}}]
date = ['2022-09-04', '2022-08-28']
return render_template('index.html', date=date, data=data)
Here is the result I got:

Django display list of dictionary in template - dict key is a 'variable'

I am using Django 4.0 to display a frontend page which source data is a list of dict.
I want to order the keys of the dict and then display all dict in the list in the same order.
Here is my views.py:
def UserGoalstatus(request, promise_token):
print("__UserGoalstatus__")
from cmd_utils import Retrieve_goal
data = Retrieve_goal(promise_token)
keys = set()
for item in data:
keys.update(set(item))
key_order = sorted(keys)
context = {
"data": data,
"key_order": key_order,
}
return render(request, 'json_table.html', context)
Here is the content of my 'data' variable:
[
{'goal_key': '286815', 'goal_type': 'hotelreservation', 'goal_id': 16149845, 'promise_token': '9ba51cbc-830b-64d603904099', 'campaign_id': 1002204, 'properties': {'price': 100, 'created': '2022-06-13 10:48:34', 'checkout': '2022-06-13', 'currency_code': 'USD', 'completed_booking_status': 1}},
{'goal_key': '1208107', 'goal_type': 'hotelreservation', 'goal_id': 16149846, 'promise_token': '9ba51cbc-830b-64d603904099', 'campaign_id': 1002204, 'properties': {'price': 100, 'created': '2022-06-13 10:48:35', 'checkout': '2022-06-13', 'currency_code': 'USD', 'completed_booking_status': 1}}
]
Here is my html file which I would like to print all content in data in the order of 'key_order'
<table id="dtBasicExample" class="table table-hover table-striped table-bordered" cellspacing="0" width="100%">
<thead>
<tr>
{% for key in key_order %}
<th>{{ key }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for item in data %}
<tr>
{% for key in key_order %}
<td>{{ item.get(key) }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
This part seems not right :{{ item.get(key) }} , anyone can suggest the right way to access the value mapping to the specific key ?
Here is my solution
I need to define a django template filter of my own
The key part is 'get_item' , it can parse dictionary key as 'variable' in Django html now .
For more detailed information refer to links below:
Django guide
stackoverflow answer
views.py
# customized template for html
from django.template.defaulttags import register
#register.filter
def get_item(dictionary, key):
return dictionary.get(key)
in json_table.html
<table id="dtBasicExample" class="table table-hover table-striped table-bordered" cellspacing="0" width="100%">
<thead>
<tr>
{% for key in key_order %}
<th>{{ key }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for item in data %}
<tr>
{% for key in key_order %}
<td>{{ item | get_item:key}}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>

Not able to send checkbox data from all pagination in datatable from template to view in django

I have a datatable in my django template in which there is a checkbox next to every row to send the row data to a view function to make some mass updations in django model. But problem is if the multiple rows are on the same page in pagination then i can send the data accurately BUT if i select row 2 from page 1 and row 5 from page 3 only the row value from page 3 will be sent to the view function.!
TEMPLATE.HTML
{% block jquery %}
<script type="text/javascript" class="init">
$(document).ready( function ($) {
var $submit = $("#updiv").hide(),
$cbs = $('input[name="updelegate"]').click(function() {
$submit.toggle( $cbs.is(":checked") );
});
$('#myTable').DataTable({
dom: 'lBfrtip',
"pageLength": 1,
"language": {
"emptyTable": "No Delegates Available",
"sSearch": "Search Delegates: ",
"info": " Showing _START_-_END_ out of Total _TOTAL_ Delegates",
}
});
});
</script>
{% endblock %}
<form id="myForm" action="{% url 'mass-delegates' %}" method="POST">
{% csrf_token %}
<table id="myTable" class="table table-striped table-bordered" style="width:100%">
<thead class="thead-dark">
<tr>
<th></th>
<th scope="col">#</th>
<th scope="col">Name</th>
<th scope="col">Email</th>
<th scope="col">Phone</th>
<th scope="col">Company</th>
<th scope="col">Designation</th>
<th scope="col">Address</th>
<th scope="col">City</th>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
{% for del in delegates %}
<tr>
<td>
<label class="container">
<input type="checkbox" id="updelegate" name="updelegate"
value="{{ del.id }}">
<span class="checkmark"></span>
</label>
</td>
<td>{{ del.id }}</td>
<td>{{ del.first_name }} {{ del.last_name }}</td>
<td>{{ del.email }}</td>
<td>{{ del.phone }}</td>
<td>{{ del.company }}</td>
<td>{{ del.designation }}</td>
<td>{{ del.address }}</td>
<td>{{ del.city }} ({{ del.pincode }})</td>
<td>
View
</td>
<td>
Edit
</td>
</tr>
{% endfor %}
</tbody>
</table>
<div id="updiv">
<select name="eventid">
{% for ev in events %}
<option value="{{ ev.id }}">{{ ev.name }}</option>
{% endfor %}
</select>
<input type="submit" onclick="return confirm('Confirm Adding to Event?');" class="upbtn"
name="update" value="Add to Event"/>
</div>
</form>
VIEW.PY
def mass_delegates(request):
if request.method == 'POST':
toupdate = request.POST.getlist('updelegate')
eventid = request.POST.get('eventid')
array_length = len(toupdate)
for i in range(array_length):
if not EventDelegate.objects.filter(event_id=eventid, delegate_id=toupdate[i]).exists():
EventDelegate.objects.create(event_id=eventid, delegate_id=toupdate[i])
return event_det(request, eventid)
Instead of using the checkboxes, you can directly use the select attribute in the Datatables api. Check Select Rows in Datatables
Moreover, Since you want to select multiple rows at once, you might consider checking Multi Select rows in Datatables out
You can add the id in the 0th column, then
dataTable = $(.selector).Datatable()
dataTable.columns([0]).visible(false);
You can hide the column like that and then when you send your request, you still have your id

How do I show/hide an entire column when a button is clicked?

I have a webapp and the results page that returns a table with multiple columns, I want my button to either hide or show the column.
I tried creating a function that does this and then call the function onclick
<button onclick="myFunction()">Show/Hide</button>
<script>
function myFunction() {
var x = document.getElementById("myDIV");
if (x.style.display === "none") {
x.style.display = "block";
} else {
x.style.display = "none";
}
}
</script>
this is the table it produces, and I want one of the columns to hide and show
<table class="table table-sm">
<thead>
<tr>
<th scope="col">Table</th>
<th scope="col">Column</th>
<th scope="col">Description</th>
<th scope="col">Data Type</th>
<th scope="col">Length</th>
<th scope="col" id="myDIV">Data Stewards</th>
</tr>
</thead>
<tbody>
{% for r in results %}
<tr>
<td>{{r.tbl_name}}</td>
<td>{{r.col_name}}</td>
{% if r.FreeText!="nan" %}
<td>{{r.FreeText}}</td>
{% else %}
<td></td>
{% endif %}
<td>{{r.DataType_Name}}</td>
<td>{{r.DataType_MaxLength}}</td>
{% if r.tag_cat_name=="Data Stewards" %}
<td> {{r.tag_name}}</td>
{% else %}
<td></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
in this format it only hides/shows the Data Stewards column heading, not the entire column
You could give the td, which you want to show/hide, the same class. Assuming, that you want to do that for the Data Stewards, it could look something like this:
HTML:
<table class="table table-sm">
<thead>
<tr>
<th scope="col">Table</th>
<th scope="col">Column</th>
<th scope="col">Description</th>
<th scope="col">Data Type</th>
<th scope="col">Length</th>
<th scope="col" class="myDIVs">Data Stewards</th>
</tr>
</thead>
<tbody>
{% for r in results %}
<tr>
<td>{{r.tbl_name}}</td>
<td>{{r.col_name}}</td>
{% if r.FreeText!="nan" %}
<td>{{r.FreeText}}</td>
{% else %}
<td></td>
{% endif %}
<td>{{r.DataType_Name}}</td>
<td>{{r.DataType_MaxLength}}</td>
{% if r.tag_cat_name=="Data Stewards" %}
<td class="myDIVs"> {{r.tag_name}}</td>
{% else %}
<td class="myDIVs"></td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
JS:
function myFunction() {
const myDIVs = document.getElementsByClassName("myDIVs");
for (let i = 0; i < myDivs.length; i++) {
if (myDivs[i].style.display === "none") {
myDivs[i].style.display = "block";
} else {
myDivs[i].style.display = "none";
}
}
}

jinja2: building table by iterating down columns instead of across rows

If I have the following lists:
headers = ['Name', 'Age']
rows = [['Johnny', 30], ['Zack', 20]]
I can easily make a table via Jinja2 (https://jsfiddle.net/equbh9du/1/):
<table class="table table-bordered table-hover">
<thead>
<tr>
{% for h in headers %}
<td>{{ h }}</td>
{% endfor %
</tr>
</thead>
<tbody>
{% for row in rows %}
<tr>
{% for item in row %}
<td>{{ item }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
I'm noticing it's much easier (and more organized) to return my data as a dictionary:
d = {'Name': ['Johnny', 'Zack'], 'Age': [30, 20]}
Is there an easy way to build the table I built above using this dict. I imagine I need to finish the iteration down each column before continuing to the next column (in the example above I finish the iteration across each row before continuing to the next row).
This is the code I have so far but I'm getting a messed up table (https://jsfiddle.net/j164fqy9/1/):
<table class="table table-bordered table-hover">
<thead>
<tr>
{% for h in d %}
<td>{{ h }}</td>
{% endfor %
</tr>
</thead>
<tbody>
{% for h, col_values in d.items() %}
{% for item in col_values %}
<tr>
<td>{{ item }}</td>
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
EDIT: If HTML standard prevents iterating down columns first, then I need to construct the headers and rows from d. Is below the best way to do this?
headers = [h for h in d]
rows = [[l[i] for h, l in d.items()] for i in range(len(d['Name']))]
If you allways have the same number of items in col_values this should work fine :
{% for i in range(d['Name']|count) %}
<tr>
{% for k in d %}
<td>{{ d[k][i] }}</td>
{% endfor %}
</tr>
{% endfor %}

Categories

Resources