Setting matrix table in Django

Asked

Viewed 533 times

3

I have two tables, in the example (any) of the figure below i have the table Paises and the table Energia

http://www.biodieselbr.com/i/energia/custo-geracao-energia.gif

Setting a third table in Django I would have something with the fields

pais, energia, valor

Áustria, Carvão, 3.6

Áustria, Ciclo combinado de gás, 3.4

and so on.

Question: How I would mount this table in the template as it is in the image?

Edited:

@mgibsonbr I adapted to my model, see the code below.

def quotation_list(request):
    stores = list(Store.objects.all())
    products = list(Product.objects.all())
    # indice
    index_store = {store.id: index for index, store in enumerate(stores)}
    index_product = {product.id: index for index,
                     product in enumerate(products)}
    # dados para o template
    cabecalho = ["Lojas"] + [store.store for store in stores]
    linhas = [([product.product] + [None for store in stores])
              for product in products]

    for pev in Quotation.objects.all():
        linhas[index_store[pev.store_id]][
            index_product[pev.product_id]] = pev.price

But the following mistake.

inserir a descrição da imagem aqui

Alias, how do I return the items in context to render on the page? return.

  • What are your models? Country and Energy? There is no relationship between these two models?

1 answer

4


I would recommend treating your data on view before sending to template:

paises = list(Paises.objects.all())    # Filtre e ordene como achar melhor
energias = list(Energia.objects.all()) # idem

# Auxiliares
indices_pais = { pais.id:indice for indice,pais in enumerate(paises) }
indices_energia = { energia.id:indice for indice,energia in enumerate(energias) }

# Dados para o template
cabecalho = ["País"] + [energia.nome for energia in energias]
linhas = [( [pais.nome] + [None for energia in energias] ) for pais in paises]

for pev in PaisEnergia.objects.all(): # Filtre conforme os países e energias usados
    linhas[indices_pais[pev.pais_id]][indices_energia[pev.energia_id]+1] = pev.valor

Then you would send cabecalho and linhas to the template and render as a table. Note that if any country/energy is missing it will appear as None (you can customize this in creating linhas).

Example of how this could be rendered in a template:

<table>
    <thead>
        <tr>
        {% for item in cabecalho %}
            <th>{{ item }}</th>
        {% endfor %}
        </tr>
    </thead>
    <tbody>
    {% for linha in linhas %}
        <tr>
        {% for item in linha %}
            <td>{{ item }}</td>
        {% endfor %}
        </tr>
    {% endfor %}
    </tbody>
</table>

Remember that if you want to highlight the first column for example (the name of the country) you can do this using forloop.first, or maybe if you want the lines with alternating colors (for readability) can use forloop.counter, etc..

    {% for linha in linhas %}
        <tr class="{% if forloop.counter|divisibleby:2 %}cinza{% else %}azul{% endif %}">
        {% for item in linha %}
            <td{% if forloop.first %} class="bold"{% endif %}>{{ item }}</td>
        {% endfor %}
        </tr>
    {% endfor %}
  • I edited my question because it generated an error.

  • 1

    I believe you reversed the indexes by adapting the answer. Try linhas[index_product[pev.product_id]][index_store[pev.store_id]] = pev.price

  • 1

    P.S. In addition there had been one missing +1 in the original response (as the name of the country occupies the position 0 from the list). Corrected linhas[index_product[pev.product_id]][index_store[pev.store_id]+1] = pev.price

  • and what is the function’s Return, or what should I take to the context to be rendered on the page?

  • further how do I mount the template? loop in case?

  • 2

    cabecalho and linhas. Roughly speaking, you open the table, the thead and the tr and iterates on cabecalho (one th by item); then you close these and open the tbody; iterates on lines, a tr per line, and in each row you iterate on the items (a td by item); finally closes the tbody and the table. For a simple table would be this.

  • complemented his answer: how can I put more field quantity on line? I tried for pev in Quotation.objects.all():&#xA; linhas[index_product[pev.product_id]][&#xA; index_store[pev.store_id] + 1] = pev.quantity but it wasn’t.

  • 1

    @Regisdasilva Each product has a price and quantity? If so, use a tuple: ... = (pev.price, pev.quantity). And in the template: for price, quantity in linha. Then you use the variables price and quantity instead of item.

  • Thank you Again.............

  • one more little thing: product that you had inserted before? Where is it, because now it is gone, and even if I put pev.product it does not appear, and before it was the index 0 of the list of each line, now it no longer appears.

  • 1

    @Regisdasilva Oh, of course, the first index is different from the others... Well, the thing is already complicating a bit, but you can start by making the first element also a tuple of size 2 - linhas = [( [(pais.nome,None)] + [None for energia in energias] ) for pais in paises] - pro for keep working - and then give special treatment to the first item - using forloop.first as suggested. If that is not enough, and you want me to explain better, please open a new question, because this is already turning into a "chameleon question" hehe :)

  • now it is enough, I will not complicate no more. Now I understand your logic. Thanks.

Show 7 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.