4

I have a pandas DataFrame and I want to show this DataFrame into my Django template. But every time the code compiles successfully without showing any table in my Django web app. What am I missing here? My DataFrame looks like this:

enter image description here

and my html looks like:

<div class="row" style="margin-bottom: 20px;">
        <div class="col-md-3">

        </div>
        <div class="col-md-9">
            <div class="card" style="width: auto;">
                <div class="card-body">
                    <h3 class="h3">Total match data and Profit Mergin</h3>
                    <br>
                    <table class="table table-striped">
                        <tr>
                            <th>Total Contest</th>
                            <th>Total Entry Amount</th>
                            <th>Total Seat</th>
                            <th>Total Winning Amount</th>
                            <th>Total Team Capacity</th>
                            <th>Profit Mergin</th>

                        {% for value in final_data.iterrows %}
                            
                        <tr>
                            <td>{{ value.0 }}</td>
                            <td>{{ value.1 }}</td>
                            <td>{{ value.2 }}</td>
                            <td>{{ value.3 }}</td>
                            <td>{{ value.4 }}</td>
                            <td>{{ value.5 }}</td>
                        </tr>
                        {% endfor %}
                    </table>
                </div>
            </div>
        </div>
    </div>

I tried final_data.iterrows but still got the same result. What should I do now?

4
  • Please include how your python script is set up. Is the final_data provided to the template? Commented Apr 4, 2020 at 6:08
  • This is probably not a solution you are looking for but there is something like pandas.pydata.org/pandas-docs/stable/reference/api/… Commented Apr 4, 2020 at 12:48
  • @ClayWahlstrom this is how i provided final_data to my template: final_df = pd.concat([df, df1], axis=1) # final_df = final_df.to_html() return render(request, 'dashboard/conversion.html', {'conversion': conversion, 'sdate': sdate, 'edate': edate, 'final_data': final_df}) else: return render(request, 'dashboard/conversion.html') hope this helps you to understand my problem. Commented Apr 4, 2020 at 18:11
  • I think you are missing a second return value, because iterrows return a tuple. Try with {% for index, value in final_data.iterrows %} Commented Oct 7, 2021 at 11:14

4 Answers 4

11

This a basic html table that shows a pandas dataframe in a django template:

<table>
  <tr>
    {% for col in df.columns %}
      <td>
        {{col}}
      </td>
    {% endfor %}
  </tr>
    {% for index, row in df.iterrows %}
      <tr>
        {% for cell in row %}
          <td>
            {{cell}}
          </td>
        {% endfor %}
      </tr>
    {% endfor %}
</table>

This one is not showing the index, so if you want to render it, you could pass df.reset_index() to the template.

Sign up to request clarification or add additional context in comments.

1 Comment

Interesting. Seems it would be useful for OpenPyXl object as well.
5

Looks like there are two options:

  1. Leave the DataFrame as-is and then use a statement in your template.

    Currently, you're using the pandas.DataFrame.iterrows method but it is not called.

    Call the method by adding () at the end of final_data.iterrows.

    (Also, make sure to close your table header row with </tr>.)

  2. Convert the DataFrame to HTML and then use an expression in your template.

    As @david-sielski mentions, consider using the pandas.DataFrame.to_html method.

    Take a look at this example of How to render Pandas DataFrame as HTML Table?

    Uncomment the final_df = final_df.to_html() line and replace the table with {{ final_data }}.

    (Also, make sure to add your styling classes using the classes kwarg.)

Check out how to use developer tools to inspect your HTML if you haven't already.

Comment if you have any questions,

Clay

2 Comments

thanks for the reply. I tried both ways multiple times but it didn't work at all. Now, I simply convert my whole dataframe into numpy array and then pass it to my template to render my table. That way it worked. May be i need deeper understanding in pandas to play with it.
There is another alternative. Convert DataFrame to dictionary and create a custom template. Please see my answer.
3

You can create a custom filter in Django to convert your pandas DataFrame to an HTML table using the pandas to_html() method.

Create a new file called filters.py inside a folder called templatetags in your Django app directory.

my_app/
  __init__.py
  models.py
  views.py
  etc..
  templatetags/
     __init__.py
     filters.py
  templates/
     index.html

In filters.py, define the filter df_to_html as follows:

from django import template
import pandas as pd
from django.utils.safestring import mark_safe

register = template.Library()

@register.filter(name="df_to_html")
def df_to_html(df: pd.DataFrame):
    return mark_safe( df.to_html() )

Now you can use the filter in your index.html template file as follows:

{% load custom_filters %} 
<!doctype html>
<html lang="en">
    ...
   {{ df | df_to_html}}

django has documentation about filters here: How to create custom template tags and filters

Comments

0

Another option similar to Pablo Guerrero's would be to convert the dataframe to a dictionary with "split" orient.

If index is needed, reset the index before sending df to context:

view.py

df = df.reset_index()
context["datatable"] = df.to_dict(orient="split", index=False)

template.html

<table>
  <thead>
    <tr>
      {% for column in datatable.columns %}
      <td>{{ column }}</td>
      {% endfor %}
    </tr>
  </thead>
  <tbody>
    {% for row in datatable.data %}
    <tr>
      {% for cell in row %}
      <td>{{ cell }}</td>
      {% endfor %}
    </tr>
    {% endfor %}
  </tbody>
</table>

Alternatively, if you do not want or cannot reset the index for any reason try this other code instead. This code works with multi-index. The difference in this case is that you need to do "tight" orient, rather than "split". Changing index=False, will hide the index.

view.py

context["datatable"] = df.to_dict(orient="tight", index=True)

template.html

<table>
  <thead>
    <tr>
      {% if datatable.index_names %}
      {% for index_name in datatable.index_names %}
      <td>
        {% if index_name != None %}
        {{index_name}}
        {% endif %}
      </td>
      {% endfor %}
      {% endif %}
      {% for column in datatable.columns %}
      <td>{{ column }}</td>
      {% endfor %}
    </tr>
  </thead>
  <tbody>
    {% for row in datatable.data %}
    <tr>
      {% if datatable.index %}
      {% for index in datatable.index %}
      {% if forloop.counter0 == forloop.parentloop.counter0 %}
      {% if index|length > 0 %}
      {% for i in index %}
      <td>{{i}}</td>
      {% endfor %}
      {% else %}
      <td>{{index}}</td>
      {% endif %}
      {% endif %}
      {% endfor %}
      {% endif %}
      {% for cell in row %}
      <td>{{ cell }}</td>
      {% endfor %}
    </tr>
    {% endfor %}
  </tbody>
</table>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.