OrangeBubbles
OrangeBubbles

Reputation: 5

Display queryset results by month in template

Id like to group the results of my queryset in a table by month with the month name as a header for each table.

I have a model like so:

class Tenant(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    telephone = models.CharField(max_length=30)
    email = models.CharField(max_length=30)
    contract_end = models.DateField(blank=False)

    def __str__(self):
        return u'%s %s' % (self.first_name, self.last_name)

View like so:

def expired_contracts(request):
    now = datetime.datetime.now()
    tenant_queryset = Tenant.objects.all()
    expired_list = []

    for x in range(0, 12):
        date = now + relativedelta(months=x)
        expired = tenant_queryset.filter(
            contract_end__year=date.year,
            contract_end__month=date.month
            )
        expired_list += expired

context = {"expired_list": expired_list}

return render(request, "expired_template.html", context)

Template:

{% for tenant in expired_list %}
<table>
<tr>
<td>{{ tenant.first_name }}</td>
<td>{{ tenant.telephone }}</td>
<td>{{ tenant.contract_end }}</td>
</tr>
</table>
{% endfor %}

I guess I could create a bunch of empty lists and populate them with a loop and if statements, but that seems a little much.

Any other way I could go about this?

Thanks!

Upvotes: 0

Views: 781

Answers (1)

Iain Shelvington
Iain Shelvington

Reputation: 32294

itertools.groupby() is an excellent tool for grouping your list.

First you should order your object by the attribute that you are grouping by

tenant_queryset = Tenant.objects.order_by('contract_end')

Grouping by month can be achieved by using itertools.groupby and formatting the date as the month's name as a string date.strftime('%B')

context = {
    "expired_list": itertools.groupby(
        expired_list, 
        lambda t: t.contract_end.strftime('%B')
    )
}

You can then loop over the months and the tenants for that month in the template like so

{% for month, tenants in expired_list %}
<h3>{{ month }}</h3>
<table>
    {% for tenant in tenants %}
    <tr>
        <td>{{ tenant.first_name }}</td>
        <td>{{ tenant.telephone }}</td>
        <td>{{ tenant.contract_end }}</td>
    </tr>
    {% endfor %}
</table>
{% endfor %}

Upvotes: 1

Related Questions