django template variable number of fields build of table from queryset - django

I'm trying to build a table in a template based on a variable number of fields.
The code I'm using is:
<table id="custom_report_table" class="display" width="100%">
<thead>
{% for field in fields %}
<th>{{ field }}</th>
{% endfor %}
</thead>
<tdody>
{% for CI in CIs %}
<tr>
<td>{{ CI }}</td>
</tr>
{% endfor %}
</tdody>
</table>
fields is a list with all the fields and CIs is a queryset with the data that needs to go into the table.
The problem is that I usually know the name of the fields so I can call each on individually when creating the cells in the usual way:
{{CI.field1}}
{{CI.field2}}
....
But now I can't hard code the fields' names as they are variable and come from the list.
Is there a way to do this?
Thanks,
Isaac

Just iterate again over CIs using items
{% for key,value in CIs.items %}
<td>{{ key }} {{value}}</td>
{%endof%}

If you only want to print items that are in fields:
{% for field_name, field_value in CIs.items %}
{% if field_name in fields %}
<th>{{ field_name }}</th>
<td>{{ field_value }}</td>
{% endif %}
{%endof%}

Solved by using .values in the queryset creation in the view.
And to reference the foreign keys for each field I had to build up the list of values with a list of field_name_foreign_field.
As the names for all foreign key fields followed a standard rule, it was quite easy with a for loop in the view.

Related

Summarizing values for each row in a table dynamically generated from django context variables

So I have the following table in my template:
<tbody>
{% for user in users %}
<tr>
<td>{{ user.title }} </td>
{% for fruit in fruits %}
{{ sum|add:user|get_attr:fruit }}
<td>{{ user|get_attr:fruit }} </td>
{% endfor %}
{% for vegetable in vegetables %}
{{ sum|add:user|get_attr:vegetable }}
<td>{{ user|get_attr:vegetable }} </td>
{% endfor %}
<td>{{ sum }}</td>
{% endfor %}
</tbody>
"fruits" and "vegetables" are lists passed as context from the view. The following custom filter allows me to iterate through those lists extract integer values from the model "user". The table columns are generated the same way, so this filter has to be in the table:
#register.filter
def get_attr(obj, attr):
return getattr(obj, attr)
The variable "sum" is passed as context from the view with the value 0. I'm trying to make it summarize all the relevant row variables in the template, but it remains 0. As far as I can see there are three ways I could go about this:
Solve this in the template (as I'm trying now)
Generate the value in the view (although I have no idea how I would go about this)
Add some JS to solve it (would prefer to avoid this).
How should I go about solving this?
Solved this on the back end by generating a dictionary:
views.py
sum = {}
for user in users:
identity = user.pk
score = 0
all_food = fruits + vegetables
for food in all_food:
score += getattr(user,food)
sum[identity] = score
The summarized value can now be accessed in the template by using another custom template tag:
#register.filter
def get_value(dictionary, key):
return dictionary.get(key)
Adding it to the template:
{{ sum|get_value:user.pk }}

Django database filter in front end

I have queries like following that I would like to implement it in front end:
MembershipPayment.objects.filter(group__name=tg.group_name).are_valid().count()
MembershipPayment.objects.filter(group__name=tg.group_name).Not_valid().count()
I know that I can pass this from view to front-end HTML, but the problem is that in the front end I have a query-set containing many "group"s. so I need to run a similar query for each of those "group"s.
I need something along these lines [this code of course won't work] in front:
{% for rec in groups %}
<tr>
<td>{{ MembershipPayment.objects.filter(group__name=tg.group_name).are_valid.count }}</td>
<td>{{ MembershipPayment.objects.filter(group__name=tg.group_name).not_valid.count }}</td>
</tr>
{% endfor %}
So I was wondering how can I achieve this without changing my model structure (if possible).
Why don't you do that logic in your view, by building a dict for each of your group, like:
def your_view(request):
...
groups: dict = dict()
for group_name in group_names:
groups[group_name]: int = MembershipPayment.objects.filter(group__name=group_name).are_valid().count()
return render(request,'your_template.html', {'groups': groups})
..and then pass it to your template, like:
{% for key, value in groups.items %}
<tr>
<td>{{key}}</td>
<td>{{value}}</td>
</tr>
{% endfor %}
...key being the group name, value being the group count.
I ended up passing a dictionary like this in view:
groups_statistics={group1:{monthly_balance:250,weekly_balance:3000},group2:{monthly_balance:250,weekly_balance:3000}}
and then looping through its value as:
{% for rec,stat_dic in groups_statistics.items %}
<tr>
<td>{{ stat_dic.weekly_balance| get_value_from_dict:rec }}</td>
<td>{{ stat_dic.monthly_balance| get_value_from_dict:rec }}</td>
</tr>
{% endfor %}
here get_value_from_dict is a customized tag defined in dictionarytags.py as:
from django import template
register = template.Library()
#register.filter('get_value_from_dict')
def get_value_from_dict(dict_data, key):
"""
usage example {{ your_dict|get_value_from_dict:your_key }}
"""
if key:
return dict_data.get(key)
in the following folder:
my app>"templatetag" folder.
this folder contains:
__ init __.py
and
dictionarytags.py
and then in html I have this line in upper part:
{% load dictionarytags %}

How do I refrain from showing repeat datetime data in a django template forloop?

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>

Django: List all where one field combines all its unique values

I got stuck. Problem I have is that I would like to create a list of objects.all() but where all objects, where one ForeignKey is the same, should be combined to one entry in a list.
My Model:
class TournamentStandings(models.Model):
tournament = models.ForeignKey(Tournament, on_delete=models.CASCADE)
player = models.ForeignKey(Player, on_delete=models.CASCADE)
player_place = models.FloatField(verbose_name=u"Place")
The list I would like to get is something like this:
ID | Player | Tournament| Place
1 | Name_1 | Tournament_1, Tournament_2| Place_on_tournament_1, P_o_t_2
2 |Name_2 |Tournament_1, Tournament_2| Place_on_tournament_1, P_o_t_2
So the ForeignKey(Player) would be the one I would like to limit and combine entries. I tried the generic view for objects.all() and the loop in my template:
{% for player in ranking_list %}
<tr>
<td>{{ ranking_list.id }}</td>
<td>{{ ranking_list.player }}</td>
<td>{{ ranking_list.tournament }}</td>
<td> {{ ranking_list.player_place }} </td>
</tr>
{% endfor %}
It didn't work. Any hints ??
Add an order_by to your query so that standings for the same player are sequential, and pass the result into itertools.groupby to get "sublists" (all standings for the same player grouped together). You can then process/format those in any way you like.
I used a little bit different aproach.
I used annotate in my views.py:
ranking_list = TournamentStandings.objects.values('player__name').annotate(Sum('player_points'))
return render(request, 'rankings.html', {'ranking_list': ranking_list})
Then in my template I show column with player__name and player_points_sum. Sorting is done by webstack_django_sorting in template so users can decide by wich column and what order they want the results are shown.
template.html:
{% load sorting_tags %}
<table class="table table-bordered">
<thead>
<tr>
<th>{% anchor player__name _("Gracz") %}</th>
<th>{% anchor player_points__sum _("Punkty") %}</th>
</tr>
</thead>
{% load static %}
<tbody>
{% autosort ranking_list %}
{% for ranking_list in ranking_list %}
<tr>
<td>{{ ranking_list.player__name }}</td>
<td> {{ ranking_list.player_points__sum }} </td>
</tr>
{% endfor %}
</tbody>
</table>

Using complex variables in django templates

In the template below, user.group is a number and it has to be shown as group_name.get(user.group) Are there any ability to pass to template group_name dict and use group_name.get(user.group) inside template?
<table>
{% for user in users %}
<tr>
<td>{{ user.name }}</td>
<td>{{ user.age }}</td>
<td>{{ user.group}}</td>
</tr>
{% endfor %}
</table>
In the spirit of django this logic should live in the code, not in the template. Can't you add a method user.get_group() that returns the group?
No, the dot notation doesn't allow for looking up names by variable value.
I would do this in the view, if it's specific to this one template.
for user in users:
users.group_name = group_name.get(user.group)
{% for user in users %}
{{ user.group_name }}
{% endfor %}
If it's applicable to all users, do as jammon suggested and define a method on User
Out of curiosity, can I see your models? Just curious why group is a number and where group_name comes from.