Rowspan and grouping in Django template - python

I have many rows in a queryset. Many of the rows share the same value in two fields.
I want to show the entire queryset in a table but I don't want to print those values which are the same multiple times.
My output would be something like
mood, age, id
=============
glad, 31, 1
, , 2
, , 3
, 32, 4
, , 5
sad, 31, 6
, , 7
, 34, 8
, , 9
, , 10
happy, 40, 11
I hope it makes sense. When multiple rows share the same value I don't want to print them again. I'm using the rowspan attribute to make the rows fill the number of rows which share the same values.
I know how to do with only one field:
{% regroup my_queryset by mood as mood_list %}
{% for mood in mood_list %}
{% for node in mood.list %}
<tr>
{% if forloop.first %}
<td rowspan="{{ mood.list|length }}">{{ mood.grouper }}</td>
{% endif %}
<td>{{ node.id }}</td>
</tr>
{% endfor %}
{% endfor %}
but I have no idea how to accomplish the same when both mood and age should 'fill multiple rows'. I guess there must be some good way as I've seen other sites doing the same with many fields (e.g. in business intelligence tools).

Using the example from here and the parentloop hint from here, I have created the following code:
{% if my_queryset %}
{% regroup my_queryset by mood as data_by_mood %}
<table border="1">
<thead>
<caption>Data</caption>
<tr><th>mood</th><th>age</th><th>id</th></tr>
</thead>
<tbody>
{% for data0 in data_by_mood %}
{% regroup data0.list by age as data0_by_age %}
{% for data1 in data0_by_age %}
{% for data in data1.list %}
<tr>
{% if forloop.first %}
{% if forloop.parentloop.first %}
<td rowspan="{{ data0.list|length }}">{{ data0.grouper }}</td>
{% endif %}
<td rowspan="{{ data1.list|length }}">{{ data1.grouper }}</td>
{% endif %}
<td>{{ data.id }}</td>
</tr>
{% endfor %}
{% endfor %}
{% endfor %}
</tbody>
</table>
{% endif %}
I hope it helps (it worked for me for a similar problem).

Related

Python Jinja2 filtering

if my table is like this
how can I output the number of events with the same name, like test should be 5 and hello should be 3.
Edit:
Here's my Jinja2 code snippet
{% for event in events %}
{% set count = 0 %}
<tr>
<td>{{ event.name }}</td>
{% for ticket in tickets %}
{% if ticket.event_name == event.name%}
{% set count = count + 1 %}
{% endif %}
{% endfor %}
<td>{{count}}<td>
<td>
But its not counting right
Never mind, I was able to solve it.
{% for event in events %}
{% set count = namespace(value=0) %}
<tr>
<td>{{ event.name }}</td>
{% for ticket in tickets %}
{% if ticket.event_name == event.name%}
{% set count.value = count.value + 1 %}
{% endif %}
{% endfor %}
<td>{{count.value}}<td>
<td>

How to show in Django queryset dict-key and -values seperately in template?

I have the this output in the browser from HTML template:
{'coin__name': 'Bitcoin', 'total': Decimal('1498824')}
{'coin__name': 'Ripple', 'total': Decimal('335227')}
How can I show in an html template separately the key and the value(without saying Decimal)?
Desired outcome:
Bitcoin, 1498824
Ripple , 335227
I provide the query and the html template below:
views.py:
test = filtered_transaction_query_by_user.values('coin__name').annotate( total = (Sum('trade_price' ) * Sum('number_of_coins'))).order_by('-total')
template.html
<table class="table table-striped">
<tr>
<th>Current dict pair</th>
<th>Just the name of the crypto</th>
<th>Just the price of the crypto</th>
</tr>
{% for item in test %}
<tr>
<td>{{ item }}</td>
<td>{{ }}</td>
<td>{{ }}</td>
</tr>
{% endfor %}
Update template with below code:
{{ test }} <!-- test is list of dictonaries -->
<br>
{% for item in test %} <!-- Loop to get each item(sub dictonary) from list-->
<br>
{% for key,value in item.items %} <!-- Getting key values pairs from each sub dictonary item -->
{% if forloop.last %} <!-- Checking if last iteration of loop just to add "::" after each value -->
{{ value }} <!-- only displying values not keys from each sub dictionary -->
{%else%}
{{value }} ,
{% endif %}
{% endfor %}
{% endfor %}
Refer to this answer for removing decimal from result.
Django: remove Decimal prefix from queryset annotated field, when requesting values
Try fetching both the key and the value from the dictionary in the loop:
{% for key, value in test.items %}
<tr>
<td>{{ key }}</td>
<td>{{ value }}</td>
</tr>
{% endfor %}
If you want to format Decimal value see docs

Can't output data in page

i have 2 tables in DB wallet(id,name) and balance(id,wallet_id)
i need table consisting of 2 cells (post,date)
where will all wallets in first cell and them balance in second
{% for wallets1 in wallets %}
<tr>
{% for balance1 in balance %}
{% if balance1.wallet_id == wallets1.id %}
<td> {{ balance1.balance }}</td>
{% endif %} {% endfor %}
{% endfor %}
if we have balance of coin we print balance
if balance1.wallet_id need print "0"
The difficulty next. If i do that
{% for wallets1 in wallets %}
<tr>
{% for balance1 in balance %}
{% if balance1.wallet_id == wallets1.id %}
<td> {{ balance1.balance }}</td>
{% else %}
<td> 0</td>
{% endif %} {% endfor %}
{% endfor %}
zero will be printed many times
views
wallets = Wallet.objects.all()
balance = User_balance.objects.filter(user_id= user.id)
args['wallets'] = wallets
args['balance'] = balance
return render_to_response("coins.html", args, user.id)
model
class Wallet(models.Model):
name = models.CharField(max_length=100)
class User_balance(models.Model):
user_id = models.IntegerField()
wallet_id = models.IntegerField()
balance = models.CharField(max_length=100)
You didn't post your view nor models so we have to assume a couple things but basically you're doing it wrong. Since balances have a foreign key on wallets, you don't have to loop over all balances for each wallets, you can just use the reverse relationship:
{% for wallet in wallets %}
<tr>
{% for balance in wallet.balance_set.all %}
<td> {{ balance.balance }}</td>
{% else %}
<td> 0</td>
{% endfor %}
</tr>
{% endfor %}
you must annotate balance in your view like this
wallers = Wallet.objects.all().annotate(total_balance=models.Count('balance'))
...
return render(request, 'template.html', {"wallets": wallets})
then in your html print wallets like this
<table>
<tr><th>wallet</th><th>balance</th></tr>
{% for wallet in wallets %}
<tr>
<td>{{ wallet.name }}</td>
<td>{{ wallet.total_balance|default:0 }}</td>
</tr>
{% endfor %}
</table>

How to globally define a counter in jinja2 so that it will remember its last value

Here is my code. I want that after the ending of the for loop the count should remember its last value so that i can check whether it entered in the if clause under for or not. But here it is not remembering the last value and all the time print "no coupons available" along with the coupons even if it find coupons.
So what is the solution to do so??
{% set count = 1 %}
{% for x in coupon_codes %}
{% if x[2]=="example.com" %}
<tr>
<td><code>{{ x[0] }}</code></td>
<td>{{ x[1] }}</td>
{% set count = count + 1 %}
</tr>
{% endif %}
{% endfor %}
{% if count==1 %}
<b>{% print "No Coupons Available." %}</b>
{% endif %}
You can use the filtered for feature of Jinja2:
{% for x in coupon_codes if x[2]=="example.com" %}
<tr>
<td><code>{{ x[0] }}</code></td>
<td>{{ x[1] }}</td>
</tr>
{% else %}
<b>No Coupons Available.</b>
{% endfor %}

django table cell color based on expression

python 2.6, with Django 1.3.1 on Redhat 6.3
In Django how would I go about changing the background colour of a table cell depending on it's value, as in if it is over 10 it's red, between 7 and 9 it's orange, below 7 is green etc..
The data is coming from a non django database/model.
I am using a standard template to iterate over the table, but would have no problem using a custom template for this.
I see the following
Link
that deals with changing cell colour but it seems to be based on a concrete value in the cell as opposed to being within a range.
using the following test code for a view
def dashboard(request):
if request.user.is_authenticated():
user = request.user.first_name
else:
return redirect('/bcpm/login')
table_headers = ['Colmun1','Column2','Column3']
table_data = [['test1',2,3],['test2',2,4],['test3',5,5]]
page_title = 'Dashboard'
template_dict = {'header_list':table_headers, 'page_title':page_title,
'results':table_data,'username':user}
return render_to_response('dashboard.html',template_dict)enter code here
and the following generic table template:
<table border=1 width=98% style="margin-left:12px;">
<tr>
{% for item in header_list %}
<th>{{ item }}</th>
{% endfor %}
</tr>
{% for row in results %}
<tr>
{% for line in row %}
<td>{{line}}</td>
{% endfor %}
</tr>
{% endfor %}
</table>
Thanks.
Almost solved;
With the help of brianbuck below i came up with the following,
in the view:
def dashboard(request):
if request.user.is_authenticated():
user = request.user.first_name
else:
return redirect('/login'
table_headers = ['Column1','Column2','Column3']
table_data = [['name','thing',8],['name','thing',5]]
page_title = 'Dashboard'
template_dict = {'header_list':table_headers, 'page_title':page_title,
'results':table_data,'username':user}
return render_to_response('dashboard.html',template_dict)
in the template;
<table border=1 width=68% style="margin-left:12px;">
<tr>
{% for item in header_list %}
<th>{{ item }}</th>
{% endfor %}
</tr>
{% for element in results %}
<tr>
<td> {{ element.0 }} </td>
<td> {{ element.1 }} </td>
{% if element.3 > 7 %} <td class="red"> {{ element.3 }} </td>
{% else %} <td class="green"> {{ element.3 }} </td> {% endif %}
</tr>
{% endfor %}
</table>
{% endif %}
I really could not get it to do an {% if or %}
When I tried to set it up to do a
"greater than or equal to 7 or less than or equal to 8"
it would always evaluate to this expression for a number higher than 7, even though the first if statement should be true for anything higher than 9.
I am using Django 1.3 and I think there may be some limitations of the if/else and the multiple evaluations, either way I have it 80% working with two values red/green and that is good enough for the moment.
Thank you all.
Got it to work like this;
{% for element in results %}
<tr>
<td> {{ element.0 }} </td>
<td> {{ element.1 }} </td>
<td> {{ element.2 }} </td>
<td> {{ element.3 }} </td>
{% if element.4 > 8 %} <td class="red"> {{ element.4 }} </td>
{% else %}{% if element.4 > 8 or element.4 >= 5 %} <td class="orange"> {{ element.4 }} </td>
{%else %}{% if element.4 < 5 %}<td class="green"> {{ element.4 }} </td>
{% endif %}{% endif %}{% endif %}
<td> {{ element.5 }} </td>
This would not be required if you have a version of Django that supports elif or if you add some of the django snippets that are available to extend your django installation.
Hurrah.
This assumes you have three classes named:
td.red {
backgroundColor: red;
}
td.orange {
backgroundColor: orange;
}
td.green {
backgroundColor: green;
}
...
Django 1.3 doesn't have elif so you will probably have to do it a bit more clunky.
<td class="
{% if val >= 10 %}red{% endif %}
{% if val >= 7 or val <= 9 %}orange{% endif %}
{% if val < 7 %}green{% endif %}">
{{ val }}
</td>
I wanted to do this only in admin.py.
Let's say your column is called col :
You want to set the column to green if its value is bigger than 0 and to red if the opposite is true.
def TableAdmin(admin.ModelAdmin)
def col_(self, obj):
green_style = "<script>document.querySelectorAll('.green_table_elem').forEach(elem => { elem.parentElement.style.background = 'green'; })</script>"
red_style = "<script>document.querySelectorAll('.red_table_elem').forEach(elem => { elem.parentElement.style.background = 'red'; })</script>"
if obj.col > 0:
return mark_safe(f'<div class="green_table_elem">{obj.col}</div> {green_style}')
else:
return mark_safe(f'<div class="red_table_elem">{obj.col}</div> {red_style}')
list_display = ('col_',)
This colors the td (column) itself and not the added div like some answers do.

Categories