Skip to content

Commit

Permalink
feat: Add a publisher model, use for traceability page initially
Browse files Browse the repository at this point in the history
This speeds up load times from seconds to ~150ms.
  • Loading branch information
Bjwebb committed Dec 20, 2024
1 parent 9abccd3 commit bf46620
Show file tree
Hide file tree
Showing 10 changed files with 142 additions and 24 deletions.
33 changes: 16 additions & 17 deletions dashboard/templates/traceability.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,49 +23,48 @@
<th>Percentage Traceable Spend</th>
</tr></thead>
<tbody>
{% for publisher_title,publisher in publishers_ordered_by_title %}
{% set publisher_stats = func.get_publisher_stats(publisher) %}
{% for publisher in publishers %}
<tr>
<td><a href="{% if publisher %}{{ url("dash-headlines-publisher-detail", args=[publisher]) }}{% endif %}">{{ publisher_title }}</a></td>
<td><a href="{% if publisher %}{{ url("dash-headlines-publisher-detail", args=[publisher.slug]) }}{% endif %}">{{ publisher.title }}</a></td>
<td>
{%- if publisher_stats.traceable_activities_by_publisher_id -%}
{{ '{:,}'.format(publisher_stats.traceable_activities_by_publisher_id) }}
{%- if publisher.traceable_activities_by_publisher_id -%}
{{ '{:,}'.format(publisher.traceable_activities_by_publisher_id) }}
{%- else -%}
0
{%- endif -%}
</td>
<td>
{%- if publisher_stats.traceable_activities_by_publisher_id_denominator -%}
{{ '{:,}'.format(publisher_stats.traceable_activities_by_publisher_id_denominator) }}
{%- if publisher.traceable_activities_by_publisher_id_denominator -%}
{{ '{:,}'.format(publisher.traceable_activities_by_publisher_id_denominator) }}
{%- else -%}
0
{%- endif -%}
</td>
<td>
{%- if publisher_stats.traceable_activities_by_publisher_id and publisher_stats.traceable_activities_by_publisher_id_denominator -%}
{{ (publisher_stats.traceable_activities_by_publisher_id / publisher_stats.traceable_activities_by_publisher_id_denominator * 100) | round_nicely }}
{%- elif publisher_stats.traceable_activities_by_publisher_id_denominator -%}
{%- if publisher.traceable_activities_by_publisher_id and publisher.traceable_activities_by_publisher_id_denominator -%}
{{ (publisher.traceable_activities_by_publisher_id / publisher.traceable_activities_by_publisher_id_denominator * 100) | round_nicely }}
{%- elif publisher.traceable_activities_by_publisher_id_denominator -%}
0
{%- endif -%}
</td>
<td>
{%- if publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id -%}
{{ '{:,.2f}'.format(publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id) }}
{%- if publisher.traceable_sum_commitments_and_disbursements_by_publisher_id -%}
{{ '{:,.2f}'.format(publisher.traceable_sum_commitments_and_disbursements_by_publisher_id) }}
{%- else -%}
0.00
{%- endif -%}
</td>
<td>
{%- if publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator -%}
{{ '{:,.2f}'.format(publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator) }}
{%- if publisher.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator -%}
{{ '{:,.2f}'.format(publisher.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator) }}
{%- else -%}
0.00
{%- endif -%}
</td>
<td>
{%- if publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id and publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator -%}
{{ (publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id / publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator * 100) | round_nicely }}
{%- elif publisher_stats.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator -%}
{%- if publisher.traceable_sum_commitments_and_disbursements_by_publisher_id and publisher.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator -%}
{{ (publisher.traceable_sum_commitments_and_disbursements_by_publisher_id / publisher.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator * 100) | round_nicely }}
{%- elif publisher.traceable_sum_commitments_and_disbursements_by_publisher_id_denominator -%}
0
{%- endif -%}
</td>
Expand Down
15 changes: 15 additions & 0 deletions dashboard/ui/management/commands/dashboard_import.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from django.core.management.base import BaseCommand
from django.db import transaction

from data import get_publisher_stats, publishers_ordered_by_title
from ui.models import Publisher


class Command(BaseCommand):
@transaction.atomic
def handle(self, *args, **options):
Publisher.objects.all().delete()
for publisher_title, publisher_slug in publishers_ordered_by_title:
stats_json = dict(get_publisher_stats(publisher_slug))
publisher = Publisher(title=publisher_title, slug=publisher_slug, stats_json=stats_json)
publisher.save()
62 changes: 62 additions & 0 deletions dashboard/ui/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Generated by Django 5.1.4 on 2024-12-20 13:31

from django.db import migrations, models


class Migration(migrations.Migration):

initial = True

dependencies = []

operations = [
migrations.CreateModel(
name="Publisher",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("slug", models.CharField()),
("title", models.CharField()),
("stats_json", models.JSONField()),
(
"traceable_sum_commitments_and_disbursements_by_publisher_id_den",
models.GeneratedField(
db_persist=True,
expression=models.F(
"stats_json__traceable_sum_commitments_and_disbursements_by_publisher_id_denominator"
),
output_field=models.JSONField(),
),
),
(
"activities",
models.GeneratedField(
db_persist=True, expression=models.F("stats_json__activities"), output_field=models.JSONField()
),
),
(
"traceable_activities_by_publisher_id",
models.GeneratedField(
db_persist=True,
expression=models.F("stats_json__traceable_activities_by_publisher_id"),
output_field=models.JSONField(),
),
),
(
"traceable_activities_by_publisher_id_denominator",
models.GeneratedField(
db_persist=True,
expression=models.F("stats_json__traceable_activities_by_publisher_id_denominator"),
output_field=models.JSONField(),
),
),
(
"traceable_sum_commitments_and_disbursements_by_publisher_id",
models.GeneratedField(
db_persist=True,
expression=models.F("stats_json__traceable_sum_commitments_and_disbursements_by_publisher_id"),
output_field=models.JSONField(),
),
),
],
),
]
Empty file.
33 changes: 33 additions & 0 deletions dashboard/ui/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import hashlib

from django.db import models


class Publisher(models.Model):
slug = models.CharField()
title = models.CharField()
stats_json = models.JSONField()
# too long
traceable_sum_commitments_and_disbursements_by_publisher_id_den = models.GeneratedField(
expression=models.F("stats_json__traceable_sum_commitments_and_disbursements_by_publisher_id_denominator"),
output_field=models.JSONField(),
db_persist=True,
)

@property
def traceable_sum_commitments_and_disbursements_by_publisher_id_denominator(self):
return self.traceable_sum_commitments_and_disbursements_by_publisher_id_den


for key in [
"activities",
"traceable_activities_by_publisher_id",
"traceable_activities_by_publisher_id_denominator",
"traceable_sum_commitments_and_disbursements_by_publisher_id",
]:
Publisher.add_to_class(
key,
models.GeneratedField(
expression=models.F(f"stats_json__{key}"), output_field=models.JSONField(), db_persist=True
),
)
8 changes: 2 additions & 6 deletions dashboard/ui/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
# Application definition

INSTALLED_APPS = [
"ui",
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
Expand Down Expand Up @@ -93,12 +94,7 @@
# Database
# https://docs.djangoproject.com/en/5.1/ref/settings/#databases

DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": BASE_DIR / "db.sqlite3",
}
}
DATABASES = {"default": env.db()}


# Password validation
Expand Down
4 changes: 3 additions & 1 deletion dashboard/ui/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import summary_stats
import text
import timeliness
import ui.models
import ui.template_funcs
import vars
from data import (
Expand Down Expand Up @@ -161,6 +162,7 @@ def _make_context(page_name: str, include_large_dicts: bool = True):
},
publisher_name=publisher_name,
publishers_ordered_by_title=publishers_ordered_by_title,
publishers=ui.models.Publisher.objects.all().defer("stats_json"),
github_issues=github_issues,
MAJOR_VERSIONS=MAJOR_VERSIONS,
expected_versions=vars.expected_versions,
Expand Down Expand Up @@ -493,7 +495,7 @@ def exploringdata_dates(request):

def exploringdata_traceability(request):
template = loader.get_template("traceability.html")
return HttpResponse(template.render(_make_context("traceability"), request))
return HttpResponse(template.render(_make_context("traceability", include_large_dicts=False), request))


#
Expand Down
1 change: 1 addition & 0 deletions requirements.in
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
django
django-environ
psycopg
gunicorn
flask
frozen-flask
Expand Down
4 changes: 4 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ packaging==24.1
# matplotlib
pillow==11.0.0
# via matplotlib
psycopg==3.2.3
# via -r requirements.in
pyparsing==3.2.0
# via matplotlib
python-dateutil==2.9.0.post0
Expand All @@ -81,6 +83,8 @@ sqlparse==0.5.1
# via django
tqdm==4.67.0
# via -r requirements.in
typing-extensions==4.12.2
# via psycopg
urllib3==2.2.3
# via requests
werkzeug==3.1.2
Expand Down
6 changes: 6 additions & 0 deletions requirements_dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ platformdirs==4.3.6
# via black
pluggy==1.5.0
# via pytest
psycopg==3.2.3
# via -r requirements.txt
pycodestyle==2.12.1
# via flake8
pyflakes==3.2.0
Expand Down Expand Up @@ -158,6 +160,10 @@ sqlparse==0.5.1
# django
tqdm==4.67.0
# via -r requirements.txt
typing-extensions==4.12.2
# via
# -r requirements.txt
# psycopg
urllib3==2.2.3
# via
# -r requirements.txt
Expand Down

0 comments on commit bf46620

Please sign in to comment.