4

I have a Django project, in which one of my views is displaying a number of tables based on information stored in the database. The view is defined as follows:

def pipeline(request):
    ...
    tables = []
    def make_table(detailed_status, projects, status_view=False, first_table=False):
        ...
        table_context_map = {
            Project.ds2: {'fields': [['date added',1], ['site visit date',1], ['initial exc VAT',1]]},
            ...
            # Similar lines to populate the tables with data from the database
            ...
        }
        table_context = table_context_map[detailed_status]
        ...
        table_context['fields'] = [['project name',1], ['town',1], ['postcode',1], ['contact name',1]] + table_context['fields']
        table = render_to_string('.../....html', table_context)
    ...
    return render(request, 'abc.html', context)

What I'd like to do, is at a column to each table created by this view, and insert an 'autonumber' in that column for every row in the table. The tables will be populated dynamically, based on a database query whenever the view is run and the webpage loaded, I just want to number the list of items in each table as it's created.

How would I do this? I am knew to Python Django, so any help or guidance would be much appreciated.

Edit

The part of the HTML that is currently displaying these tables in the webpage looks like this:

<div class="content">
    {% block tables %}
        {% for table in tables %}

                {# Only shows table headers on first table (css first of type on multisection thead) #}

                {{table}}

        {% endfor %}
    {% endblock tables %}
</div>

Edit

The HTML for the file passed into the render_to_string(...) view has the following structure:

{% load getters money_handling staticfiles utilities %}

{% if projects %}
    <div class="table-container m-t-lg">

        <table class="multisection pipeline left">
            <tr class="sub-summary">
                <th colspan="4"><a href="?detailed_status={{detailed_status}}"><h3 class="p-l-sm">{{detailed_status_str}}</h3></a></th>
                {% if total_i %}<th>Initial exc VAT: {{total_i|money:"£"}}</th>{% endif %}
                {% if total_u %}<th>Latest exc VAT: {{total_u|money:"£"}}</th>{% else %}
                <th></th>
                {% endif %}
            </tr>
        </table>
        <table class="multisection pipeline left m-b-xl">
            <tr class="summary">
                <th style="width: 3em;"></th>
                {% for field in fields %}
                    <th class="text-sm p-l-sm p-t-sm p-b-sm" style="width:{{widths|getval:forloop.counter0}}">
                    {% if field.1 %}
                        {% if sort == field.0 and not reverse %}
                            <a href="?sort=-{{field.0}}&detailed_status={{detailed_status}}">{{field.0}}</a>
                        {% else %}
                            <a href="?sort={{field.0}}&detailed_status={{detailed_status}}">{{field.0}}</a>
                        {% endif %}
                    {% else %}
                        {{field.0}}
                    {% endif %}
                    </th>
                    {# Make all have the same number of columns (8) #}
                    {% if forloop.last %}
                        {% for i in ',,,,,,,,' %}
                            {% if forloop.counter|add:forloop.parentloop.counter0 < 11 %}
                                <th>&nbsp;</th>

                            {% endif %}
                        {% endfor %}
                        {% if detailed_status == "ds4"|ds %}
                            <th></th>
                        {% endif %}
                    {% endif %}
                {% endfor %}
            </tr>
            {% with user.employee.full_name|is:'Nick Ross' as summary_link %}

            {% for project in projects %}
                <tr data-project-id="{{project.id}}" class="even {% if project.office == 2 %} col{% endif %}">
                    {% with initial_details=project.initial_details survey=project.survey  %}
                        {# Open lightbox #}
                        <td>
                            {# ERF(22/11/2016 @ 1450) Add a counter to display table row numbers #}
                            {% if user.is_superuser %}
                                <a class="gallery-loader" data-project-id="{{project.id}}"><i class="icon info"></i></a>

                                {% if forloop.first and first_table %}
                                    <div id="iframe_gallery_wrap">

                                        <a href="#p1" class="gallery">
                                            <div id="p1">
                                                <iframe class="lightbox-content" src="{% url 'projects:description' project.id %}report/" width="1200" height="800" id="p1" style="border:none;" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
                                            </div>
                                        </a> 
Noble-Surfer
  • 3,052
  • 11
  • 73
  • 118
  • so, If understand correctly, you fetch data from database and, when rendering, you want to add a column indicating the row number? I mean is it just for display purposes? – Jonatas CD Nov 22 '16 at 13:05
  • Yes, I'm fetching the data from a database, and the row number is just for display purposes. Just to clarify, the row number should just be the number of the row in the display table- it shouldn't be fetched from the database. – Noble-Surfer Nov 22 '16 at 13:10
  • so @neverwalkaloner answer is the way to go indeed – Jonatas CD Nov 22 '16 at 13:12

1 Answers1

12

Probaly forloop.counter is what you are looking for.

Just use it in your template like this:

<ul>
{% for data in data_list %}
    <li>{{ forloop.counter }}</li>
{% endfor %}
</ul>

As for your file hope my modifications will work (marked it with your username):

    {% load getters money_handling staticfiles utilities %}

{% if projects %}
    <div class="table-container m-t-lg">

        <table class="multisection pipeline left">
            <tr class="sub-summary">
                <th colspan="4"><a href="?detailed_status={{detailed_status}}"><h3 class="p-l-sm">{{detailed_status_str}}</h3></a></th>
                {% if total_i %}<th>Initial exc VAT: {{total_i|money:"£"}}</th>{% endif %}
                {% if total_u %}<th>Latest exc VAT: {{total_u|money:"£"}}</th>{% else %}
                <th></th>
                {% endif %}
            </tr>
        </table>
        <table class="multisection pipeline left m-b-xl">
            <tr class="summary">
                <th style="width: 3em;"></th>
                <th>Number</th> @someone2088 
                {% for field in fields %}
                    <th class="text-sm p-l-sm p-t-sm p-b-sm" style="width:{{widths|getval:forloop.counter0}}">
                    {% if field.1 %}
                        {% if sort == field.0 and not reverse %}
                            <a href="?sort=-{{field.0}}&detailed_status={{detailed_status}}">{{field.0}}</a>
                        {% else %}
                            <a href="?sort={{field.0}}&detailed_status={{detailed_status}}">{{field.0}}</a>
                        {% endif %}
                    {% else %}
                        {{field.0}}
                    {% endif %}
                    </th>
                    {# Make all have the same number of columns (8) #}
                    {% if forloop.last %}
                        {% for i in ',,,,,,,,' %}
                            {% if forloop.counter|add:forloop.parentloop.counter0 < 11 %}
                                <th>&nbsp;</th>

                            {% endif %}
                        {% endfor %}
                        {% if detailed_status == "ds4"|ds %}
                            <th></th>
                        {% endif %}
                    {% endif %}
                {% endfor %}
            </tr>
            {% with user.employee.full_name|is:'Nick Ross' as summary_link %}

            {% for project in projects %}
                <tr data-project-id="{{project.id}}" class="even {% if project.office == 2 %} col{% endif %}">
                    {% with initial_details=project.initial_details survey=project.survey  %}
                        {# Open lightbox #}
                        <td>{{ forloop.counter }}</td> @someone2088
                        <td>
                            {# ERF(22/11/2016 @ 1450) Add a counter to display table row numbers #}
                            {% if user.is_superuser %}
                                <a class="gallery-loader" data-project-id="{{project.id}}"><i class="icon info"></i></a>

                                {% if forloop.first and first_table %}
                                    <div id="iframe_gallery_wrap">

                                        <a href="#p1" class="gallery">
                                            <div id="p1">
                                                <iframe class="lightbox-content" src="{% url 'projects:description' project.id %}report/" width="1200" height="800" id="p1" style="border:none;" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
                                            </div>
                                        </a> 
neverwalkaloner
  • 46,181
  • 7
  • 92
  • 100
  • Thanks for your answer- that certainly sounds like it's what I want, but I'm just not sure how I'd incorporate it into the HTML as it currently stands because that seems to be displaying each table as a whole, not as rows/ columns, etc... I've updated my OP to show the HTML for the tables as they're displayed at the moment. – Noble-Surfer Nov 22 '16 at 13:18
  • Would I just nest your `for` loop inside the `for` loop that's already there? i.e `for table ((for row in table){...}) in tables` – Noble-Surfer Nov 22 '16 at 13:21
  • @someone2088 not sure will this work but you can try to do this: {% for table in tables %}{% for r in table %}{{ r }}{% endfor %}{% endfor %}. Btw could you show all code of pipeline view?
    – neverwalkaloner Nov 22 '16 at 13:30
  • The `make_table` view is nested inside the `pipeline` view- and I'm fairly sure it's only the code inside `make_table` that I'm interested in, as I only want to change what's displayed in the tables- the rest of the page is working/ displaying as I want it to, so I expect that the rest of the view is fine, and don't think it has any effect on what's displayed by the `make_table` view... – Noble-Surfer Nov 22 '16 at 13:39
  • Looking at it again, I think there's one or two more lines of `make_table` that I think are relevant- I'll paste those in now. – Noble-Surfer Nov 22 '16 at 13:41
  • I've added the extra couple of lines at the end of `def make_table`, and I think I'll need to add the 'autonumber' field to the line: `table_context['fields'] = [['project name',1], ['town',1], ['postcode',1], ['contact name',1]] + table_context['fields']` - would that be right? How would I do it if so? – Noble-Surfer Nov 22 '16 at 13:46
  • @someone2088 which template is using here render_to_string('.../....html', table_context)? I think you can insert forloop.counter there. – neverwalkaloner Nov 22 '16 at 14:02
  • The `render_to_string(.../...html', table_context)` isn't in a template- that's in the `make_table(...)` view... Or do you mean the HTML template that it's rendering to (i.e. the html file in the `()` parenthesis? – Noble-Surfer Nov 22 '16 at 14:20
  • @someone2088 Yes, I mean HTML file .../...html using by render_to_string. Open this file and paste there code from my answer. – neverwalkaloner Nov 22 '16 at 14:26
  • I'm not sure I know which HTML file you mean... `render_to_string(...)` is using a different HTML file to the one at the URL on which I am seeing the table. The URL I see in the browser when I view the page with the table on it is: `.../projects/pipeline`, which is why I'm looking in the `pipeline` view. The `make_table` view that is defined inside the `pipeline` view is the one that does the `render_to_string(...)`, but it assigns that to a variable called `table`- so is the variable `table` actually the HTML file returned by `render_to_string`? i.e. an HTML file embedded within another? – Noble-Surfer Nov 22 '16 at 14:40
  • I tried pasting your code inside the HTML file used by `render_to_string`, but it didn't make a difference to what I saw displayed on the webpage. I'll update my OP now with the HTML from this file. – Noble-Surfer Nov 22 '16 at 14:42
  • @someone2088 render_to_string() is function that takes as argument template name and return rendered HTML. Show me content of HTML file which you specify as argument here `render_to_string('.../....html', table_context)` and I will try to tell you how to to add counters there. – neverwalkaloner Nov 22 '16 at 14:50
  • Thanks for your help- I've edited my OP to show the code for the `render_to_string()`, and put a comment in that where I think I need to add the counter- but I'm just not sure whether I've understood the structure of this correctly or not. – Noble-Surfer Nov 22 '16 at 15:02
  • @someone2088 updated my answer. In few words your view is working this way: function make_table() build html text with table. This HTML text then passed to pipeline() function and pipline() just added this HTML to abc.html template. So if you need to modify table, you shoud to work with template using in make_table(). I modified it, but not sure this will work. Now as you know where actually your table builded you can change those last template as you want and get any tables you like. – neverwalkaloner Nov 22 '16 at 15:22
  • That's spot on! Thanks very much for your help! – Noble-Surfer Nov 22 '16 at 15:28