问题
I want to do something very simple in Django: Print a matrix as an HTML table, and add labels for the rows and columns. These are the variables in my view:
matrix = np.array([
[101, 102, 103],
[201, 202, 203],
])
colnames = ['Foo', 'Bar', 'Barf']
rownames = ['Spam', 'Eggs']
I want a to get a table that looks like this:
Foo Bar Barf Spam 101 102 103 Eggs 201 202 203
My template code looks like this:
<table>
<tr>
<th></th>
{% for colname in colnames %}
<th>{{ colname }}</th>
{% endfor %}
</tr>
{% for rowname in rownames %}{% with forloop.counter0 as rowindex %}
<tr>
<th>{{ rowname }}</th>
{% for colname in colnames %}{% with forloop.counter0 as colindex %}
<td>TABLECELL</td>
{% endwith %}{% endfor %}
</tr>
{% endwith %}{% endfor %}
</table>
Output for different values of TABLECELL:
{{ rowindex }}, {{ colindex }}
--> table with the indices :)
{{ matrix.0.0 }}
--> table full of 101s :)
{{ matrix.rowindex.colindex }}
--> table with empty cells :(
As the first two things work, it doesn't seem crazy to assume that the last one would give the intended result. My only explanation is that rowindex
and colindex
might be strings — and of course int()
is among the many things that are forbidden in Django templates.
Does anyone know how I can make this work? Or ideally: Does anyone know how this is intended to be done in Django?
EDIT 1:
It seems I have to pass the enumerated lists to the template. I provide them as enum_colnames
and enum_rownames
, but now I can't even execute the nested for loop:
<table>
<tr>
<th></th>
{% for unused_colindex, colname in enum_colnames %}
<th>{{ colname }}</th>
{% endfor %}
</tr>
{% for rowindex, rowname in enum_rownames %}
<tr>
<th>{{ rowname }}</th>
{% for doesnt_work_anyway in enum_colnames %}
<td>You don't see me.</td>
{% endfor %}
</tr>
{% endfor %}
</table>
This gives a table with all the <th>
s filled with the correct labels, but no <td>
s at all.
EDIT 2:
I found an insanely ugly "solution", which I publish here as an example of something that "works", but is clearly not an answer to my question — how this should be done in Django. Here it comes:
derp = ['', 'Foo', 'Bar', 'Barf', 'Spam', 101, 102, 103, 'Eggs', 201, 202, 203]
iderp = enumerate(derp)
<table>
{% for i, d in iderp %}
{% if i < 4 %} <!-- if top row: th -->
{% cycle '<tr><th>' '<th>' '<th>' '<th>' %}
{% else %} <!-- else: td -->
{% cycle '<tr><th>' '<td>' '<td>' '<td>' %}
{% endif %}
{{ d }}
{% if i < 4 %} <!-- if top row: th -->
{% cycle '</th>' '</th>' '</th>' '</th></tr>' %}
{% else %} <!-- else: td -->
{% cycle '</th>' '</th>' '</td>' '</td></tr>' %}
{% endif %}
{% endfor %}
</table>
Note how it can only be used for tables of this particular width. So in this form it is not even a real solution for the initial problem.
回答1:
Thanks to Paulo Almeida for providing the two essential hints in his answer:
The table — including labels — should be built in the view.
forloop.first
can be used to put the labels in<th>
s.
table = [
['', 'Foo', 'Bar', 'Barf'],
['Spam', 101, 102, 103],
['Eggs', 201, 202, 203],
]
<table>
{% for row in table %}
<tr>
{% for cell in row %}
{% if forloop.first or forloop.parentloop.first %} <th> {% else %} <td> {% endif %}
{{ cell }}
{% if forloop.first or forloop.parentloop.first %} </th> {% else %} </td> {% endif %}
{% endfor %}
</tr>
{% endfor %}
</table>
I guess the answer to my implicit question — how the values of multidimensional arrays can be accessed from the template — is that this is not possible.
回答2:
Your problem seems to be a good use case for a feature request suggesting the use of iterables in the cycle tag. Then you could just {% cycle rownames %}
in the first <td>
.
Unfortunately, that's not possible, as far as I can see. I would take that logic away from the template and into the view (or, more likely, an utility function or model method, depending on the specifics), building a list that is easy to process in the template:
table = [
['Spam', 101, 102, 103],
['Eggs', 201, 202, 203],
]
The function to build the table might look like this:
def build_table(rownames, matrix):
table = []
for rowname, values in zip(rownames, matrix):
row = [rowname]
row.extend(values.tolist())
table.append(row)
return table
来源:https://stackoverflow.com/questions/28457774/whats-the-correct-way-to-print-a-matrix-with-labels-in-a-django-template