I've got a problem displaying items in a table, that is both regrouped by columns and rows.
I wrote an app, where employees can log a workday and set a status (office, vacation etc.)
I pass all day items to the template by:
results = Tage.objects.filter(*args, **kwargs)
In the template I regroup the columns by
{% regroup results|dictsort:"employee.id" by employee as employee_entries %}
and loop through them
<tr>
<th>Date</th>
{% for ma in employee_entries %}
<th>{{ ma.grouper }}</th>
{% endfor %}
</tr>
Thats works fine.
Next thing is regrouping the rows by the day.
{% regroup results|dictsort:"employee.id"|dictsortreversed:"starttime" by starttime|date:"d. E Y" as day_entries %}
{% for te in day_entries %}
<tr>
<th colspan="5" style="border-right: 0px;">{{ te.grouper }}</th>
</tr>
That also works fine.
Now the tricky part:
I want to display the status of the day an employee has logged by:
<tr>
<th>Status</th>
{% for result in te.list %}
<th>{{ result.status }}</th>
{% empty %}
<th></th>
{% endfor %}
</tr>
That works fine, if all employees have logged that specific day. If someone hasn't logged a day like others, all status columns are in the wrong place. Of course, that happens because te.list is not the same length as the employee list.
Has anyone an approach to such a problem? I googled around a lot, but didn't find a straight-forward solution to such a problem.
Thanks in advance
Conrad
I decided to render the table header and body inside the view and pass it to the template and render it with
{{ theader|safe }}
and so on.
The problem was too complex for the capabilities of Django's template system.
Related
In a Django application I have several html pages with a similar structure. I am already using a base_site.html template for all my project but for these other pages I would like to use a second template to create tables. These tables could have more or less rows and columns than others.
My idea was that the functions in views.py would send a list of the headers for any given page together with a dict of the data to populate the table, then in the html page I would iterate the list of headers to place the headers in the table then I would iterate the dict to populate the table with the data.
How can I have a table-template.html to use a variable say headers from every function in views.py whenever they are called?
Something like table-template.html
<h1>TEST</h1>
<table>
<tr bgcolor="#ccc">
<th>{% for h in headers %} {{ h }} {% endfor %}</th>
</tr>
</table>
Considering that every function in views.py would return its own headers list
Then how can I use it in any of the html pages
{% extends "admin/base_site.html" %}
{% load static %}
{% block content %}
{% include "table-template.html" %}
{% load static %}
{% for key,value in mydict.items %}
<table>
<tr>
<td>{{ value }}</td>
</tr>
</table>
{% endfor %}
The table-template.html could be use a slight change since you want each value in a tag
<h1>TEST</h1>
<table>
<tr bgcolor="#ccc">
{% for h in headers %}
<th> {{ h }} </th>
{% endfor %}
</tr>
</table>
This will create the correct table headers for you. You can send the headers list from your view render method in the context dictionary.
Feel free to comment if this doesn't give the complete answer you are looking for.
I actually managed to find a solution by creating a template that inherits my base_site.html and on all my other templates I will inherit my new_template.html. So it's kind of a grand parent template inheritance.
I just included all the variables I want in the template (which are all named equally across all functions in views.py) and when the template is extended in a new page it gets the values of the variables from the respective function in views.py.
SOLVED
Explanation here: Performing a getattr() style lookup in a django template
I am looking to build tables on our business website dynamically. At the moment we have multiple pages with tables and filters that allow for search but I have to go in and construct a table for each of them based on the data that should be displayed. I was hoping to find a way to use one main template file that can encompass most instances for creating a new page. The difficulty I am having is trying to loop through the data and place it in the correct cell.
(Some code has been removed for readability.)
View:
def newDynamicView(request):
jobs = Jobstable.objects.all().order_by('-index')
filter = NewFilter(data, queryset = jobs)
fields_model = filter._meta.fields
fields_text = []
for field in fields_model:
fields_text.append(FIELD_NAME_TEXT[field])
return render(request, 'MYSQLViewer/olivia.html', {'filter': filter, 'fields_model': fields_model, 'fields_display': fields_text})
Current Template (Relevant info):
<div class="table-responsive">
<table id="data_table" class="table table-dark table-bordered table-responsive">
<thead class="thead-light">
{% for field in fields_display %}
<th>{{field}}</th>
{% endfor %}
</thead>
<tbody>
{% for job in filter.qs %}
<tr>
{% for model_field in fields_model %}
<td class="pt-3-half edit {{model_field}}" contenteditable="true" id="{{model_field}}-{{job.index}}">{{job.model_field}}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
From what I understand, the problem (and possible solution?) lies in this tag:
{{job.model_field}}
My idea was to grab the job attribute using model_field but obviously, that doesn't work.
In its current state, all data is passed from view to template correctly.
Any help is greatly appreciated.
In a django template, I'm accessing objects in a list filtered by the objects' datetime.
Here's a current image of the object_list onto an HTML table:
The time part of the datetime ("11:50a.m") must remain regardless of duplicates.
However, the date part of the datetime ("September 9"), must appear only once for each unique date.
Essentially, what I'm looking for would look something like:
How would I go about achieving this effect? I've tried using {% if forloop.first %}, but I'm unable to find a way to target all "firsts" of unique dates.
This is the current code which corresponds to the first image:
{% for event in object_list %}
<tr>
<td>{{ event.datetime|date:"F j g:ia e" }}: </td>
<td>{{ event.venue }}</td>
</tr>
{% endfor %}
I've also considered not using the date of the datetime object and manually coding the dates in the HTML, but wouldn't know how to eventually tie the DOM date to the object_list according to date.
That is exactly what the ifchanged tag is for.
I would split your output into two parts, and use ifchanged on the date only.
<tr>
<td>{% ifchanged %}{{ event.datetime|date:"F j" }}{% endifchanged %}</td>
<td>{{ event.datetime|date:"g:ia e" }}: </td>
<td>{{ event.venue }}</td>
</tr>
I have a dictionary with 6 keys and each key's value is a list with 100 elements
my_dict = {"Key1":["name1", "name2", ..., "name100"],
"Key2":["id1", "id2", ..., "id100"],
...
"Key6":["type1", "type2", ..., "type100"]}
I am trying to make a table that is 100 x 6, where each column will be a list.
I have tried everything in the template and come up short every time. Is there some simple concept I am missing? Should I be manipulating the data in the backend to make it more manageable?
Edit: I probably should be more clear. I can render my template fine, I can put stuff in a table, just not how I want to.
I can do things like
<tr>
{% for i in my_dict.items %}
<td>{{i}}</td>
{% endfor %}
</tr>
Giving me 1 row with 6 columns
or
{% for items in dict.items %}
<tr>
{% for item in items %}
<td>{{item}}</td>
{% endfor %}
</tr>
{% endfor %}
giving me 6 rows and 100 columns
I could do
{% for item in dict.Key1 %}
<tr>
<td>{{item}}</td>
</tr>
{% endfor %}
Giving me 1 column and 100 rows
But I need each item, in each list, in its own column.
If I am correct, your table needs to have 6 columns and 100 rows right? If so it is difficult to do that in the template, and I would edit the data before sending it to the template. Usually you should always try to keep complicated logic like that outside of the template anyways.
View:
def get_context_data(self, **kwargs):
context = super(YOUR_CLASS_HERE, self).get_context_data(**kwargs)
# I defined each list this way just to test
my_dict = {
"Key1": ["name1", "name2", "name100"],
"Key2": ["id1", "id2", "id100"],
"Key6": ["type1", "type2", "type100"]
}
my_data = [[v[i] for k, v in my_dict.items()] for i in range(3)] # This would be range(100) for you, once again I was just testing.
context['my_data'] = my_data
return context
And in the template:
<table>
<thead>
</thead>
<tbody>
{% for row in my_data %}
<tr>
{% for entry in row %}
<td>{{ entry }}</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Edit: I believe this solution solves your problem in the best way. Granted it does the work in the view rather than the template, but you don't want to do this type of data manipulation in the template. This solution changes the data with 1 line of code:
my_data = [[v[i] for k, v in my_dict.items()] for i in range(100)]
It's much easier to do it in python than with the template tags in the template. I can't think of a way to do it in the template without writing a custom template tag. If you do use a custom template tag, then your still using python so you should have just done it in the view.
May be you are asking for this (how to render this dict on template side). Try this,I hope, I got your question right as it is not clear much otherwise make me correct.
{% for key, value_list in my_dict.items %}
# your stuff
{% for value in value_list %}
# more stuff here (2)
{% endfor %}
{% endfor %}
I want to display data in a table where there is a many-to-one relationship between my column values (Components) and my rows (Materials). There is a further many-to-one relationship between these column values and the column headers (ComponentTypes). At the moment I have implemented something similar to this in my view:
rows:
materials_list = Materials.objects.all()
columns:
component_type_list = Components.objects.filter(material__in = materials_list).values("component__name")
Establishing the values for the row in the order of the column titles:
for material in materials:
component_list = []
for component_type in component_type_list:
try:
component = material.components_set.filter(component__name = component_type['component__name'])[0].weight_pct
except:
component = 0
component_list.append(component)
material.component_list_for_table = component_list
I then pass materials and component_type_list to the template where I have the following:
<table>
<thead>
<tr>
<th>Guru ID</th>
<th>Material</br>Code</th>
{% for component_type in component_type_list %}
<th>{{ component_type.component__name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for material in materials %}
<tr>
<th>{{ material.GURU_ID }}</th>
<th>{{ material.MATERIALCODE }}</th>
{% for component in material.component_list_for_table %}
<td>{{ component|floatformat }}%</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
Even with just 50 rows (potentially ~100 columns) this operates extremely slowly. Is there a more efficient way to do it?
I have edited the code to simplify it so it may not be perfect.
My 2 cents:
use Django Debug Toolbar to check how many queries you've got and how long they take. You mention "this operates extremely slowly" but it's good to have data.
have you tried to use prefetch_related to limit queries?
I'd use Python code (like you did) to reorganise data in the records if that's too complicated through SQL.
Maybe something like this:
materials_list = Materials.objects.prefetch_related('components_set').prefetch_related('components_set__type').all()
for material in material_list:
component_list = []
# your logic here - which should run fast thanks to the prefetches.
material.component_list = component_list