How to hide duplicates in django template - table? - django

I have dict:
my_dict = {
'1': [],
'2': [],
'3': ['some_text'],
'4': ['some_text'],
'5': ['some_text'],
'6': [],
'7': ['other_text'],
'8': []
}
And I want to display this in template:
+--------+------------------------------+
| 1 | |
+--------+------------------------------+
| 2 | |
+--------+------------------------------+
| 3 | some_text |
+--------+ +
| 4 | |
+--------+ +
| 5 | |
+--------+------------------------------+
| 6 | |
+--------+------------------------------+
| 7 | other_text |
+--------+------------------------------+
| 8 | |
+--------+------------------------------+
For now I have:
{% for skey, svalue in sdict.items %}
<tr>
<td>
{{ skey }}
</td>
<td>
{% for val in svalue %}
{{ val }}
{% endfor %}
</td>
</tr>
{% endfor %}
and output:
+--------+------------------------------+
| 1 | |
+--------+------------------------------+
| 2 | |
+--------+------------------------------+
| 3 | some_text |
+--------+------------------------------+
| 4 | some_text |
+--------+------------------------------+
| 5 | some_text |
+--------+------------------------------+
| 6 | |
+--------+------------------------------+
| 7 | other_text |
+--------+------------------------------+
| 8 | |
+--------+------------------------------+
How to do it?

You could use the {% regroup %} tag with a converted version of your dictionary in conjunction with the {% ifchanged %} tag.
First, you'd need to convert your dictionary in your view to something that works with the {% regroup %} tag, for instance a list of dictionaries:
sdict_converted = [{"column_one": k, "column_two": v} for k, v in sdict.items()]
This can then be used in your template like so:
{% regroup sdict_converted|dictsort:"column_one" by "column_two" as grouped_sdict_converted %}
{% for group in grouped_sdict_converted %}
{% for item in group.list %}
<tr>
<td>
{{ item.column_one }}
</td>
{% ifchanged item.column_two %}
<td rowspan="{{ group.list|length }}">
{% for nested_value in item.column_two %}
{{ value }}
{% endfor %}
</td>
{% endifchanged %}
</tr>
{% endfor %}
{% endfor %}

Related

Get different data from Django views in table

I have CBV like this:
class MyTableViews(TemplateView):
template_name = "table.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tables'] = Table.objects.all()
return context
And I have tables like this:
<table id="t_add_row" class="table">
<thead>
<tr>
<th>Header1</th>
<th>Header2</th>
<th>Header3</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{% for item in tables %}
<tr>
<td>{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.address }}</td>
<td>
<button type="button" class="edit" data-target="#rowEditModal">x</button>
</td>
</tr>
{% endfor %}
</tbody>
</table>
That table produce something like this:
|Header1| Header2 | Header3 | Edit |
| 1 | Name1 | Address1 | x |
| 2 | Name2 | Address2 | x |
| 3 | Name3 | Address3 | x |
And I have modal form in same templates, that targeted from above table for ID=#rowEditModal:
<div class="modal-content" id="rowEditModal">
{% for t in tables %}
<div class="modal-body">
<form>
<div class="form-group">
<label for="message-text" class="control-label">Header1:</label>
<input type="text" class="form-control" id="header1" value="{{ t.id }}">
</div>
<div class="form-group">
<label for="message-text" class="control-label">Header2:</label>
<input type="text" class="form-control" id="header2" value="{{ t.name }}">
</div>
<div class="form-group">
<label for="message-text" class="control-label">Header3:</label>
<input type="text" class="form-control" id="header3" value="{{ t.address }}">
</div>
</form>
</div>
<div class="modal-footer">
<button id="btn-updaterow" class="btn">Update</button>
</div>
{% endfor %}
</div>
But when I click Edit button (x) for each row then it display same data from 1st row only:
Header1: 1
Header2: Name1
Header3: Address1
How to get different data for each row?

mathematical operations on the variable product.has_default_option

I need to perform mathematical operations on the variable product.has_default_option.
how can I do?
this is my snippet:
{% for product in products %}
<li class="{{ product.css_class }}">
<a href="{{ product.url }}">
<img alt="Image of {{ product.name | escape }}" src="{{ product.image | product_image_url | constrain: '900' }}">
<b style="font-family: 'Bevan', cursive;text-transform: uppercase;font-size: large;">{{ product.name }}</b>
<i style="font-family: 'Bevan', cursive;text-transform: uppercase;font-size: medium;">{{ product.default_price | money: theme.money_format }}</i>
<p> {{ product.default_price * 2 | money: theme.money_format }}</p>
{% case product.status %}
{% when 'active' %}
{% if product.on_sale %}<em>On Sale</em>{% endif %}
{% when 'sold-out' %}
<em>Sold Out</em>
{% when 'coming-soon' %}
<em>Coming Soon</em>
{% endcase %}
</a>
</li>
{% endfor %}
You can use the times filter, so to multiply that variable by 2 you'd do the following:
{{ product.default_price | times: 2 }}

Django fill table column based on subdict key

I have a dict in the following format:
{
'P1': {'A': [1,10], 'B': [4,5], 'C': [8,12]},
'P2': {'A': [1,10], 'E': [4,5], 'G': [8,12]},
'P3': {'C': [1,10], 'D': [4,5], 'J': [8,12]}
}
and an HTML table set-up like this:
<table>
<thead>
<tr>
<th></th>
</tr>
<tr>
<th>A</th>
<th>B</th>
<th>C</th>
<th>D</th>
<th>E</th>
<th>F</th>
<th>G</th>
<th>H</th>
<th>I</th>
<th>J</th>
</tr>
</thead>
.
.
.
what I'm trying to do is outputting the P's letter on the correct "cell", basically the data should go in the correct letter, like this:
Player | A | B | C | D | E | F | G | H | I | J |
P1 | 1 | 4 | 8 | | | | | | | |
P2 | 1 | | | | 4 | | 8 | | | |
P3 | | | 1 | 4 | | | | | | 8 |
I tried this but failed:
{% for k,v in p_dataset.items %}
<tr>
<td>{{k}}</td>
{% for letter, vals in v.items %}
<td>{% if letter == 'A' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'B' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'C' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'D' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'E' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'F' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'G' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'H' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'I' %}{{vals}}{% endif %}</td>
<td>{% if letter == 'J' %}{{vals}}{% endif %}</td>
{% endfor %}
</tr>
{% endfor %}
but all I got where a lot of exceeding tds, how should I do this?
Edit: Thinking about it, perhaps I could add all the subkeys as empty and update them on the view, but is there another way?
Thanks to Chiefir for the idea, I ended up solving it like this:
{% for k,v in p_dataset.items %}
<tr>
<td>{{k}}</td>
<td>{% if v.A %}{{v.A|join:' '}}%{% endif %}</td>
<td>{% if v.B %}{{v.B|join:' '}}%{% endif %}</td>
<td>{% if v.C %}{{v.C|join:' '}}%{% endif %}</td>
<td>{% if v.D %}{{v.D|join:' '}}%{% endif %}</td>
<td>{% if v.E %}{{v.E|join:' '}}%{% endif %}</td>
<td>{% if v.F %}{{v.F|join:' '}}%{% endif %}</td>
<td>{% if v.G %}{{v.G|join:' '}}%{% endif %}</td>
<td>{% if v.H %}{{v.H|join:' '}}%{% endif %}</td>
<td>{% if v.I %}{{v.I|join:' '}}%{% endif %}</td>
<td>{% if v.J %}{{v.J|join:' '}}%{% endif %}</td>
</tr>
{% endfor%}

How to reset cycle counter?

I have in template this:
{% for item in items %}
{% ifchanged item.st2 %}
<div class="clear"></div>
<div class="item-title">{{ item.get_st2 }}</div>
{% endifchanged %}
<div class="cell {% cycle 'clear tco1' 'tco' 'tco' 'tco2' 'clear tce1' 'tce' 'tce' 'tce2' %}">{{ item.name }}</div>
{% endfor %}
and it shows things like this:
------------------ st2 name 1 -------------------
+-----------------------------------------------+
| grey item | grey item | grey item | grey item |
+-----------------------------------------------+
| dark item | dark item | dark item | dark item |
+-----------------------------------------------+
| grey item | grey item | grey item | grey item |
+-----------------------------------------------+
| dark item | dark item | dark item | dark item |
+-----------------------------------------------+
| grey item | grey item | grey item | grey item |
+-----------------------------------------------+
------------------ st2 name 2 -------------------
+-----------------------------------------------+
| grey item | grey item | grey item | grey item |
+-----------------------------------------------+
| dark item | dark item | dark item | dark item |
+-----------------------------------------------+
and its good.
But if items on st2 name is less than 4 in one line:
------------------ st2 name 1 -------------------
+-----------------------------------------------+
| grey item | grey item | grey item | grey item |
+-----------------------------------------------+
| dark item | dark item | dark item |
+-----------------------------------+
then next looks like this:
------------------ st2 name 1 -------------------
+-----------------------------------+
| grey item | grey item | grey item |
+-----------------------------------------------+
| dark item | dark item | dark item | dark item |
+-----------------------------------------------+
because cycle coutner is still on the fourth element.
How to reset cycle tag?
You can use cycle tag with silent keyword to declare the cycle but not produce the first value. By giving the cycle tag a name, using "as" you can insert the current value of the cycle wherever you’d like. Another cycle tag with name of the variable will move cycle to the next value independently. And divisibleby tag can be used to check for last in line item:
{% cycle 'clear tco1' 'tco' 'tco' 'tco2' 'clear tce1' 'tce' 'tce' 'tce2' as cellcls silent %}
{% for item in items %}
{% ifchanged item.st2 %}
<div class="clear"></div>
<div class="item-title">{{ item.get_st2 }}</div>
{% if not forloop.counter1|divisibleby:"4" %} {# im not tested it #}
{% cycle cellcls %}
{% endif %}
{% endifchanged %}
<div class="cell {{cellcls}}">{{ item.name }}</div>
{% cycle cellcls %}
{% endfor %}
Ugly, but it works:
{% cycle '1' '2' '3' '4' as cellcount silent %}
{% cycle 'tco1' 'tco' 'tco' 'tco2' 'tce1' 'tce' 'tce' 'tce2' as cellcls silent %}
{% for item in items %}
{% ifchanged item.st2 %}
{% if not forloop.first %}
{% if cellcount|add:0 == 2 %}
{% cycle cellcls %}{% cycle cellcls %}{% cycle cellcls %}
{% cycle cellcount %}{% cycle cellcount %}{% cycle cellcount %}
{% endif %}
{% if cellcount|add:0 == 3 %}
{% cycle cellcls %}{% cycle cellcls %}
{% cycle cellcount %}{% cycle cellcount %}
{% endif %}
{% if cellcount|add:0 == 4 %}
{% cycle cellcls %}
{% cycle cellcount %}
{% endif %}
{% endif %}
<div class="clear"></div>
<div class="item-title">{{ item.get_st2 }}</div>
{% endifchanged %}
<div class="cell {{ cellcls }}" style="{{ cellcount }}">{{ item.name }}</div>
{% cycle cellcls %}
{% cycle cellcount %}
{% endfor %}
I came across same problem and write small custom template tag (works in django 1.8):
from django import template
import itertools
register = template.Library()
class ResetCycleNode(template.Node):
def __init__(self, variable_name, cycle_node):
self.variable_name = variable_name
self.cycle_node = cycle_node
def render(self, context):
cycle_iter = itertools.cycle(self.cycle_node.cyclevars)
context.render_context[self.cycle_node] = cycle_iter
context[self.variable_name] = next(cycle_iter).resolve(context)
return ''
#register.tag
def reset_cycle(parser, token, escape=False):
args = token.split_contents()
if len(args) != 2:
raise TemplateSyntaxError("'reset_cycle' tag requires exactly one argument")
name = args[1]
if not hasattr(parser, '_namedCycleNodes'):
raise TemplateSyntaxError("No named cycles in template. '%s' is not defined" % name)
if name not in parser._namedCycleNodes:
raise TemplateSyntaxError("Named cycle '%s' does not exist" % name)
return ResetCycleNode(name, parser._namedCycleNodes[name])
And then use it in template like this:
{% cycle 'clear tco1' 'tco' 'tco' 'tco2' 'clear tce1' 'tce' 'tce' 'tce2' as cellclass silent %}
{% for item in items %}
{% ifchanged item.st2 %}
<div class="clear"></div>
<div class="item-title">{{ item.get_st2 }}</div>
{% reset_cycle cellclass %}
{% endifchanged %}
<div class="cell {{ cellclass }}{% cycle cellclass %}">{{ item.name }}</div>
{% endfor %}
This is an old question, but as of Django 1.11 there is a built-in tag, resetcycle that appears to do what OP wants.

ZURB Foundation: Should I create row for every "row"?

So, Can I create one <div class="row"> and push there columns? The total length of columns will be larger 12 units. Is it bad style and I should create row for every row?
It depends on the behaviour you want. If you have more than 12 columns in a row they will wrap on to the next line as it were
more than 12 columns in one row will wrap
<div class="row">
<div class="small-2 large-4 columns">. . .</div>
<div class="small-2 large-4 columns">. . .</div>
<div class="small-2 large-4 columns">. . .</div>
<div class="small-2 large-4 columns">. . .</div>
<div class="small-2 large-4 columns">. . .</div>
</div>
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
-----------------------------------------------------------------------
| | | |
| div1 | div2 | div3 |
| | | |
-----------------------------------------------------------------------
| | |
| div4 | div5 |
| | |
-----------------------------------------------
equivalent in 2 rows
<div class="row">
<div class="small-2 large-4 columns">...</div>
<div class="small-2 large-4 columns">...</div>
<div class="small-2 large-4 columns">...</div>
</div>
<div class="row">
<div class="small-2 large-4 columns">...</div>
<div class="small-2 large-4 columns">...</div>
<div class="small-2 large-4 columns">...</div>
</div>
| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
-----------------------------------------------------------------------
| | | |
| div1 | div2 | div3 | (row 1)
| | | |
-----------------------------------------------------------------------
-----------------------------------------------
| | |
| div1 | div2 | (row 2)
| | |
-----------------------------------------------
There is a bit more detail here Understanding Div classes in Foundation 4