Skip to content

Commit

Permalink
Update template
Browse files Browse the repository at this point in the history
  • Loading branch information
estyxx committed Dec 29, 2023
1 parent d9e9600 commit baf1f75
Show file tree
Hide file tree
Showing 2 changed files with 153 additions and 83 deletions.
64 changes: 42 additions & 22 deletions backend/grants/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from django.urls import path
from django.template.response import TemplateResponse
from django.db.models import Count

from helpers.constants import GENDERS
from django import forms
from django.contrib import admin, messages
from django.db.models.query import QuerySet
Expand Down Expand Up @@ -566,8 +566,7 @@ def get_urls(self):
def summary_view(self, request):
"""
Custom view for summarizing Grant data in the Django admin.
This view aggregates
grant data by country and status, applying filters from the request.
Aggregates data by country and status, and applies request filters.
"""
# Initialize statuses
statuses = Grant.Status.choices
Expand All @@ -582,32 +581,43 @@ def summary_view(self, request):
)

# Process and aggregate data for display
summary, totals_by_status = self._process_grant_data(grants_data, statuses)
(
summary,
totals_by_status,
totals_per_continent,
) = self._aggregate_data_by_country(grants_data, statuses)
gender_summary = self._aggregate_data_by_gender(filtered_grants, statuses)
human_readable_filters = self._format_filters_for_display(filter_params)
# Sort the summary data
sorted_summary = dict(sorted(summary.items(), key=lambda x: (x[0][0], x[0][2])))

context = {
"template_data": self._prepare_template_data(summary, statuses),
"summary": sorted_summary,
"statuses": statuses,
"genders": {code: name for code, name in GENDERS},
"total": filtered_grants.count(),
"totals_by_status": totals_by_status,
"totals_per_continent": totals_per_continent,
"gender_summary": gender_summary,
"filters": human_readable_filters,
**self.admin_site.each_context(request),
}
return TemplateResponse(request, "admin/grants/grant_summary.html", context)

def _process_grant_data(self, grants_data, statuses):
def _aggregate_data_by_country(self, grants_data, statuses):
"""
Processes grant data for aggregation.
Aggregates grant data by country and status.
"""

summary = {}
totals_by_status = {status[0]: 0 for status in statuses}
totals_per_continent = {}

for data in grants_data:
country = countries.get(code=data["travelling_from"])
continent = country.continent.name if country else "Unknown"
country_name = f"{country.name} {country.emoji}" if country else "Unknown"
country_code = country.code if country else "Unknown"

key = (continent, country_name, country_code)

# Initialize country summary
Expand All @@ -617,24 +627,34 @@ def _process_grant_data(self, grants_data, statuses):
summary[key][data["status"]] += data["total"]
totals_by_status[data["status"]] += data["total"]

return summary, totals_by_status
# Update continent totals
if continent not in totals_per_continent:
totals_per_continent[continent] = {status[0]: 0 for status in statuses}
totals_per_continent[continent][data["status"]] += data["total"]

return summary, totals_by_status, totals_per_continent

def _prepare_template_data(self, summary, statuses):
def _aggregate_data_by_gender(self, filtered_grants, statuses):
"""
Prepares data for the summary view template.
Aggregates grant data by gender and status.
"""
# Sort summary data
sorted_keys = sorted(summary.keys(), key=lambda x: (x[0], x[2]))
gender_data = filtered_grants.values("user__gender", "status").annotate(
total=Count("id")
)
gender_summary = {
gender: {status[0]: 0 for status in statuses} for gender, _ in GENDERS
}
gender_summary[""] = {
status[0]: 0 for status in statuses
} # For unspecified genders

# Prepare data for template rendering
return [
{
"continent": key[0],
"country": key[1],
"counts": [summary[key].get(status[0], 0) for status in statuses],
}
for key in sorted_keys
]
for data in gender_data:
gender = data["user__gender"] if data["user__gender"] else ""
status = data["status"]
total = data["total"]
gender_summary[gender][status] += total

return gender_summary

def _format_filters_for_display(self, filter_params):
"""
Expand Down
172 changes: 111 additions & 61 deletions backend/grants/templates/admin/grants/grant_summary.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,59 @@
{% load markdownify %}
{% load localize countryname get_item %}
{% load i18n admin_urls static admin_list %}
{% load get_item %}
{% block extrastyle %}
{{ block.super }}
<link rel="stylesheet" href="{% static "admin/css/changelists.css" %}">
<style>
.back-button {
margin-bottom: 20px;
}
.back-button {
margin-bottom: 20px;
}

.back-button a.button {
padding: 6px 12px;
}
.back-button a.button {
padding: 6px 12px;
}

.back-button a.button:hover {
background-color: #e6e6e6;
}
.back-button a.button:hover {
background-color: #e6e6e6;
}

</style>
<style>
.status-filter {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #ddd;
background-color: #f9f9f9;
}
.status-filter h3 {
margin-top: 0;
}
.checkbox-list {
display: flex;
flex-wrap: wrap;
align-items: center;
}
.status-checkbox {
margin-right: 20px;
margin-bottom: 10px;
}
.status-checkbox input {
margin-right: 5px;
}

.status-filter {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #ddd;
background-color: #f9f9f9;
}

.status-filter h3 {
margin-top: 0;
}

.checkbox-list {
display: flex;
flex-wrap: wrap;
align-items: center;
}

.status-checkbox {
margin-right: 20px;
margin-bottom: 10px;
}

.status-checkbox input {
margin-right: 5px;
}

.continent-total {
border-top: 2px solid #E8E8E8;
border-bottom: 2px solid #000;
}
</style>
{% endblock %}
{% block content %}
<div class="back-button">
<a href="{% url 'admin:grants_grant_changelist' %}" class="button">Back to List</a>
<a href="{% url 'admin:grants_grant_changelist' %}?{{ request.GET.urlencode }}"
class="button">Back to List</a>
</div>
<h1>Grant Summary</h1>
<!-- Display Active Filters -->
Expand Down Expand Up @@ -73,7 +82,8 @@ <h3>Toggle Status Columns</h3>
{% endfor %}
</div>
</div>
<table id="grantSummaryTable">
<h2>by Country</h2>
<table id="grantsByCountry">
<thead>
<tr>
<th>Continent</th>
Expand All @@ -82,32 +92,72 @@ <h3>Toggle Status Columns</h3>
</tr>
</thead>
<tbody>
{% for row in template_data %}
<tbody>
{% for key, counts in summary.items %}
{% with continent=key.0 country=key.1 %}
{% ifchanged continent %}
<tr class="continent-total">
<td colspan="2">
<strong>Total for {{ continent }}:</strong>
</td>
{% for status in statuses %}
<td>
<strong>{{ totals_per_continent|get_item:continent|get_item:status.0|default:"0" }}</strong>
</td>
{% endfor %}
</tr>
{% endifchanged %}
<tr>
<td>{{ continent }}</td>
<td>{{ country }}</td>
{% for status in statuses %}<td>{{ counts|get_item:status.0|default:"0" }}</td>{% endfor %}
</tr>
{% endwith %}
{% endfor %}
</tbody>
<tfoot>
<tr>
<td>{{ row.continent }}</td>
<td>{{ row.country }}</td>
{% for count in row.counts %}<td>{{ count }}</td>{% endfor %}
<td colspan="2">Total Grants: {{ total }}</td>
{% for count in totals_by_status.values %}<td>{{ count }}</td>{% endfor %}
</tr>
{% endfor %}
</tbody>
<tfoot>
<tr>
<td colspan="2 }}">Total Grants: {{ total }}</td>
{% for count in totals_by_status.values %}<td>{{ count }}</td>{% endfor %}
</tr>
</tfoot>
</table>
<script>
document.addEventListener('DOMContentLoaded', function () {
var checkboxes = document.querySelectorAll('.toggle-column');
checkboxes.forEach(function(checkbox) {
checkbox.addEventListener('change', function() {
var column = document.getElementById('grantSummaryTable').querySelectorAll('td:nth-child(' + checkbox.dataset.column + '),th:nth-child(' + checkbox.dataset.column + ')');
column.forEach(function(cell) {
cell.style.display = checkbox.checked ? '' : 'none';
});
</tfoot>
</table>
<h2>by Gender</h2>
<table id="grantsByGender">
<thead>
<tr>
<th>Gender</th>
<th></th>
{% for status in statuses %}<th>{{ status.1|title }}</th>{% endfor %}
</tr>
</thead>
<tbody>
{% for gender, gender_data in gender_summary.items %}
<tr>
<td>{{ genders|get_item:gender|default:"Not Specified" }}</td>
<td></td>
{% for status in statuses %}<td>{{ gender_data|get_item:status.0|default:"0" }}</td>{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
<script>
document.addEventListener('DOMContentLoaded', function() {
var checkboxes = document.querySelectorAll('.toggle-column');
checkboxes.forEach(function(checkbox) {
checkbox.addEventListener('change', function() {
var countryColumn = document.getElementById('grantsByCountry').querySelectorAll('td:nth-child(' + checkbox.dataset.column + '),th:nth-child(' + checkbox.dataset.column + ')');
countryColumn.forEach(function(cell) {
cell.style.display = checkbox.checked ? '' : 'none';
});

var genderColumn = document.getElementById('grantsByGender').querySelectorAll('td:nth-child(' + checkbox.dataset.column + '),th:nth-child(' + checkbox.dataset.column + ')');
genderColumn.forEach(function(cell) {
cell.style.display = checkbox.checked ? '' : 'none';
});

});
});
});
});
});
</script>
{% endblock %}
</script>
{% endblock %}

0 comments on commit baf1f75

Please sign in to comment.