2011-07-30 12 views
5

Tengo un diccionario de Python con el lugar donde cada tecla corresponde a un título, y la lista asociada a cada encabezado contiene un número arbitrario de valores:el modo de hacer un diccionario Python como una tabla HTML con columnas verticales

data = { 
    "heading1": ['h1-val1', 'h1-val2', 'h1-val3', ], 
    "heading2": ['h2-val1', ], 
    "heading3": ['h3-val1', 'h3-val2', 'h3-val3', 'h3-val4', ], 
} 

necesito para hacer esto en una plantilla de Django como una mesa, donde los valores se enumeran verticalmente debajo de cada encabezamiento, con todos los valores que faltan prestados como vacía celda de la tabla:

<table> 
<thead> 
    <tr> 
    <th>heading1</th> 
    <th>heading2</th> 
    <th>heading3</th> 
    </tr> 
</thead> 
<tbody> 
    <tr> 
    <td>h1-val1</td> 
    <td>h2-val1</td> 
    <td>h3-val1</td> 
    </tr> 
    <tr> 
    <td>h1-val2</td> 
    <td></td> 
    <td>h3-val2</td> 
    </tr> 
    <tr> 
    <td>h1-val3</td> 
    <td></td> 
    <td>h3-val3</td> 
    </tr> 
    <tr> 
    <td></td> 
    <td></td> 
    <td>h3-val4</td> 
    </tr> 
</tbody> 
</table> 

Cuál es la mejor manera de lograr ¿esta?

Mi primera inclinación es reorganizar el dict original en una matriz 2D, y simplemente pasarlo a la plantilla. Sin embargo, estoy seguro de que no soy el primero en encontrarme con este tipo de problema, y ​​tengo curiosidad de cómo otros han resuelto este problema.

ACTUALIZACIÓN: Solo como referencia, aquí está mi solución original a este problema (con lo que no estoy muy contento).

# Using the data dict from the question: 
size = max(len(data['heading1']), len(data['heading2']), len(data['heading3'])) 
matrix = [[None, None, None] for i in range(size)] # initialize an empty matrix 

# manually copy the data into the appropriate column :(
i = 0 
for item in data['heading1']: 
    matrix[i][0] = item 
    i += 1 
i = 0 
for item in data['heading2']: 
    matrix[i][1] = item 
    i += 1 
i = 0 
for item in data['heading3']: 
    matrix[i][2] = item 
    i += 1 

entonces pasa la matriz en la plantilla que parecía esto:

<table> 
<thead><tr> 
    <th>heading1</th> 
    <th>heading2</th> 
    <th>heading3</th> 
</tr></thead> 
<tbody> 
{% for row in matrix %} 
    <tr> 
    {% for col in row %} 
     <td>{% if col %}{{ col }}{% else %}&nbsp;{% endif %}</td> 
    {% endfor %} 
    </tr> 
{% endfor %} 
</tbody> 
</table> 

Respuesta

4

Si cambiamos el juego un poco, en realidad es muy fácil de cambiar esto (siempre que sus listas se llenan Ninguno ...)

from django.template import Context, Template 

data = { 
    "heading1": ['h1-val1', 'h1-val2', 'h1-val3', ], 
    "heading2": ['h2-val1', ], 
    "heading3": ['h3-val1', 'h3-val2', 'h3-val3', 'h3-val4', ], 
} 

# we'll need to split the headings from the data 
# rather than using keys() I'm just hard coding so I can control the order 
headings = ["heading1", "heading2", "heading3"] 

columns = [data[heading] for heading in headings] 

# get the length of the longest column 
max_len = len(max(columns, key=len)) 

for col in columns: 
    # padding the short columns with None 
    col += [None,] * (max_len - len(col)) 

# Then rotate the structure... 
rows = [[col[i] for col in columns] for i in range(max_len)] 


dj_template =""" 
<table> 
{# headings #} 
    <tr> 
    {% for heading in headings %} 
     <th>{{ heading }}</th> 
    {% endfor %} 
    </tr> 
{# data #} 
{% for row in data %} 
    <tr> 
     {% for val in row %} 
     <td>{{ val|default:'' }}</td> 
     {% endfor %} 
    </tr> 
{% endfor %} 
</table> 
""" 

# finally, the code I used to render the template: 
tmpl = Template(dj_template) 
tmpl.render(Context(dict(data=rows, headings=headings))) 

Para mí, esto produce la siguiente (líneas en blanco despojados):

<table> 
    <tr> 
     <th>heading1</th> 
     <th>heading2</th> 
     <th>heading3</th> 
    </tr> 
    <tr> 
     <td>h1-val1</td> 
     <td>h2-val1</td> 
     <td>h3-val1</td> 
    </tr> 
    <tr> 
     <td>h1-val2</td> 
     <td></td> 
     <td>h3-val2</td> 
    </tr> 
    <tr> 
     <td>h1-val3</td> 
     <td></td> 
     <td>h3-val3</td> 
    </tr> 
    <tr> 
     <td></td> 
     <td></td> 
     <td>h3-val4</td> 
    </tr> 
</table> 
+1

Debería haber mencionado esto anteriormente, pero la razón por la que tendrá que dividir los títulos y los datos es como arunkumar se menciona: no se puede esperar que 'dict.items()' le entregue las claves en un orden predecible. Da la casualidad de que separar los encabezados de los datos _also_ simplifica la estructura de la plantilla. –

+0

He actualizado el código para ocuparme de rellenar las listas. Debería eliminar la necesidad de inicializar la matriz vacía (por adelantado). –

0

Prueba el código de abajo. Tenga en cuenta que, dado que está utilizando una matriz asociativa para los datos, no se puede garantizar el orden en que aparecen los títulos.

print "<table>" 

print "<thead><tr>" 
order = [] 
for k in data.keys(): 
    print "<td>" + k + "</td>" 
    order.append(k) 
print "</tr></thead>" 

print "<tbody>" 
for k in order: 
    print "<tr>" 
    for v in data[k]: 
     print "<td>" + v + "</td>" 
    print "</tr>" 
print "</tbody>" 
print "</table>"  
+0

Esto no funciona Primero, necesito los datos organizados para poder pasarlos a una plantilla de Django (por supuesto, podría almacenar esto en una cadena en lugar de imprimirlo, pero preferiría que toda la presentación se hiciera en la plantilla). El segundo punto es que esto imprime todos los datos asociados con cada encabezado en su propia fila. Quiero esa información en una columna. –

2

Kenneth Reitz sugirió que también se podría resolver este problema utilizando tablib, por lo que pensé que incluyo aquí también:

import tablib 

d = tablib.Dataset() 
d.append_col(['h1-val1', 'h1-val2', 'h1-val3', ''], header="heading1") 
d.append_col(['h2-val1', 'h2-val2', '', ''], header="heading2") 
d.append_col(['h3-val1', 'h3-val2', 'h3-val3', 'h3-val4', ], header="heading3") 
d.headers = ['heading1', 'heading2', 'heading3'] 

Este vertederos de todos los datos pertinentes en un conjunto de datos, que luego se podría hacer en un molde con el siguiente:

{{ d.html }} 

que produce html que tiene este aspecto:

<table> 
<thead> 
<tr><th>heading1</th> 
<th>heading2</th> 
<th>heading3</th></tr> 
</thead> 
<tr><td>h1-val1</td> 
<td>h2-val1</td> 
<td>h3-val1</td></tr> 
<tr><td>h1-val2</td> 
<td>h2-val2</td> 
<td>h3-val2</td></tr> 
<tr><td>h1-val3</td> 
<td></td> 
<td>h3-val3</td></tr> 
<tr><td></td> 
<td></td> 
<td>h3-val4</td></tr> 
</table> 
+1

Realmente necesitaba un poco más de personalización para el html, que es la única razón por la que no utilicé esta solución. Eso y [la solución de Owen a continuación] (http: // stackoverflow.com/questions/6884250/how-to-render-a-python-dict-as-an-html-table-with-vertical-columns/6885140 # 6885140) funciona muy bien. –

Cuestiones relacionadas